Email is a technology that has been part of everyday life for more than 50 years. It’s still one of the most important methods of communication, even in the era of smartphones and apps. It provides an extremely reliable and secure way of messaging, from notifications to password resets. In some countries, email (or some form thereof) is even used as a way of communication from public authorities, having rendered mail obsolete years ago.
With this in mind, most web applications rely on email one way or another. If you own a web store, for example, you’re more likely than not already sending emails to your customers with order confirmations. This is more or less expected from such a service, as it gives customers peace of mind and a “paper” trail of their orders. But sending email reliably is a whole other topic. Due to its increase in popularity, most big email providers are very aggressive when it comes to receiving email, and will easily classify email from unknown sources as SPAM. This is when reputable email sending services come into play.
What is SendGrid?
Instead of spending time and money on setting up your own email server, your time is best spent integrating into a known and reputable email provider. SendGrid has been around for about 10 years, making them one of the kings in the industry of email communications. See, building an email server is a tricky business, where you have to build a reputation and maintain it, to avoid getting flagged by the email giants like Gmail. They have invested the research and time needed to build a powerful service, so you don’t have to.
Basic | Pro | Utra | Mega | |
Price | Free | $9.95/month | $79.95/month | $199.95/month |
Quota | 100 emails per day | 40,000 emails per month | 100,000 emails per month | 300,000 emails per month |
Pricing of SendGrid usage in RapidAPI
Of course, SendGrid has also spent a considerable amount of time building their APIs, to allow developers like you to easily integrate your apps into their robust infrastructure. They officially provide their API via RapidAPI, which makes integration and billing a whole lot easier.
What we will build
You have a customer who needs you to build an API for them. The usage is as follows: they have an app where users can see real estate listings. While swiping through the listings, they can select the ones they like and when they do, they enter their email to receive the listing’s details. The details are stored in the API you will build, in the form of a PDF file. Your API needs to be able to receive a request with the email and the listing ID, and then send the user an email with the realtor’s contact information and the corresponding PDF file as an attachment.
Requirements
Setup our project
You will need:
- Ruby
- Padrino
- A RapidAPI account
The simplest way to install Ruby is to go to the official installation instructions. Here you’ll find directions to install Ruby depending on your platform. There’s also a comparison of Ruby web frameworks here, where you can get an overview of which framework might be best suited for your project. For this project, we’ll use Padrino.
To get your RapidAPI account, just head on to rapidapi.com to sign up. Even though SendGrid’s API has a free usage tier, you’ll need a credit card. Don’t worry though, as you’ll only be charged if you go over the free usage of the plan (which is 100 emails per day, and should be enough for this tutorial).
Setup SendGrid in RapidAPI
Go SendGrid’s profile in RapidAPI. Here you’ll see a list of endpoints supported by SendGrid. Before you can use any of them, you need to subscribe to one of their plans. Like we mentioned before, they offer a free plan, which includes more than enough emails per day to be able to play around and test our code. Go ahead and subscribe to that plan:
After that, click on “Endpoints” at the top of the page. At the bottom, you will see two important strings: X-RapidAPI-Host
and X-RapidAPI-Key
. You’ll need both for the next section.
A quick example
Let’s start with a quick snippet on how to send an email using Ruby. First, you’ll have to install a library called excon
, which is a powerful yet simple networking library. This is needed as we’ll be making HTTP requests to SendGrid to send emails. Run this in your terminal:
gem install excon
After that, hop on to the interactive ruby shell, so we can play around with the API. Run irb
in your terminal, then require some dependencies:
require 'excon' require 'json'
We’ll need the JSON gem to convert Ruby structures into JSON, which is what SendGrid expects. Now, if you take a look at the sample payload for the “Send” endpoint, you’ll notice it’s quite simple:
{ "personalizations": [ { "to": [ { "email": "john@example.com" } ], "subject": "Hello, World!" } ], "from": { "email": "from_address@example.com" }, "content": [ { "type": "text/plain", "value": "Hello, World!" } ] }
Most of this you’ll recognize. There’s a “to”, a “from” and “content”. This is the most basic payload you can send to SendGrid to send an email. You can take a look at their documentation to see what other parameters you can send to customize each email. For example, you can add attachments to emails. To keep this example short, let’s just customize the options a bit to our liking. Type this in your IRB session:
payload = {} receiver = { email: 'my@email.org', name: 'John SendGrid Doe' } subject = 'Hello from RapidAPI!' from = { email: 'tutorial@rapidapi.com', name: 'RapidAPI Tutorial' } payload[:personalizations] = [] payload[:personalizations] << { subject: subject, to: [ receiver ] } payload[:from] = from payload[:content] = [] payload[:content] << { type: 'text/plain', value: 'Hello from RapidAPI! This is just a test from the console' }
Remember to substitute the recipient’s email with either your own or some temporary email for testing purposes. This is just creating a similar structure as the JSON we showed before. We’re sending an email to John Doe, adding a subject and a body. Now, let’s send it:
headers = {} headers['X-RapidAPI-Host'] = 'YOUR HOST' headers['X-RapidAPI-Key'] = 'YOUR API KEY' headers['Content-Type'] = 'application/json' Excon.post('https://rapidprod-sendgrid-v1.p.rapidapi.com/mail/send', headers: headers, body: payload.to_json)
Notice we’re setting the headers to the values we asked you to take note of previously, plus a header specifying that the content we send is JSON. Without this last header, you’ll just get an error back. You should now see an email in your inbox!
Build the API
Now that we have a grasp on how the API works, let’s build what our client asked. We’ll build this with Padrino. First, create a directory for our project:
mkdir sendgrid-api
And add a Gemfile:
# Gemfile source "https://rubygems.org" gem "sinatra" gem "excon"
Run bundle install
in your console to install the dependencies. Let’s also create a folder for our attachments:
mkdir attachments
Fill this folder with some dummy PDF files. You can use this one. We created three different files so we have some to play with:
Create the endpoint
Let’s now create our main file. Name it app.rb
and add this to it:
# app.rb require 'sinatra' require 'excon' require 'json' require 'base64' post '/request_listing' do email = params['email'] listing_id = params['listing_id'] # Load the listing attachment begin attachment = File.read(File.join('attachments', "#{listing_id}.pdf")) rescue Errno::ENOENT halt 404, 'Listing not found' end payload = { personalizations: [ { to: [ { email: email } ], subject: "Your requested information on listing #{listing_id}" } ], from: { email: 'realtor@example.org', name: 'Your local realtor' }, content: [ { type: 'text/plain', value: 'We have attached the details on the listing you requested.' } ] } # Encode and add the attachments payload[:attachments] = [ { content: Base64.strict_encode64(attachment), filename: "#{listing_id}.pdf", type: 'application/pdf' } ] # Send the email response = Excon.post( 'https://rapidprod-sendgrid-v1.p.rapidapi.com/mail/send', headers: { 'X-RapidAPI-Host': 'YOUR HOST', 'X-RapidAPI-Key': 'YOUR KEY', 'Content-Type': 'application/json' }, body: payload.to_json ) # If we managed to send the email, say so, otherwise fail if response.status == 202 status 202 else puts response.body status 500 end end
First, we import all the necessary gems. We’ll need sinatra
and excon
, but we’ll also need json
and base64
. The last one is required to be able to convert our attachments to Base 64 encoding, as is required by SendGrid. We then set up our endpoint as a POST
endpoint, call it request_listing
, and get the parameters from the request.
Next, we read the attachment from the attachments folder, and if we can’t find it we’ll just stop with a status of 404. The next big thing is to build the payload. This is pretty straightforward and there’s nothing too different from what we already saw in the previous steps. What’s new is the next highlighted section. To add an attachment, we need to encode it to Base 64 encoding. In few words, this means converting the binary contents of the PDF attachment to a string, so SendGrid can easily send it over. We’ll also set a file name and specify the type of file.
# Lines 40-46 payload[:attachments] = [ { # Encode the file content: Base64.strict_encode64(attachment), # Set a filename for the attachment filename: "#{listing_id}.pdf", # Specify the content of the file type: 'application/pdf' } ]
Lastly, we’ll send the payload to SendGrid like we did previously.
Giving our API a test
Go to your terminal and run bundle exec ruby app.rb
. This will start your server, and you should see something like this in your terminal:
[2019-11-24 23:16:49] INFO WEBrick 1.3.1 [2019-11-24 23:16:49] INFO ruby 2.3.7 (2018-03-28) [universal.x86_64-darwin18] == Sinatra (v2.0.7) has taken the stage on 4567 for development with backup from WEBrick [2019-11-24 23:16:49] INFO WEBrick::HTTPServer#start: pid=64410 port=4567
This means your server is now running on port 4567. To test it, we’ll just use cURL. In another terminal, let’s try this:
curl -d 'email=my@email.org&listing_id=unknown_property' http://localhost:4567/request_listing
Notice unknown_property
as our listing ID. We’re trying to test that our server actually says a listing can’t be found when the ID is wrong. You should see Listing not found
in your terminal. Now, let’s try a listing that does exist:
curl -d 'email=my@email.org&listing_id=property_1' http://localhost:4567/request_listing
Your terminal should now say nothing, but your inbox should have a new email with an attachment: one of the dummy PDFs.
Conclusions
Congratulations! You’ve just managed to programmatically send email with attachments using SendGrid. Their APIs give you a lot more control over your email needs than what we showed here. You should definitely take a look at Suppression Groups if you’re planning on sending non-transactional emails. This feature lets you create a sort of category (which you specify using the asm.group_id
parameter when sending email) so that users can unsubscribe. This is particularly important because you want to avoid getting marked as SPAM by your users, which affects your email reputation.
Leave a Reply