Mail Sending API perks over SMTP in Ruby on Rails using MailGun or SendGrid

Using Email APIs gives features like more probability of delivery, subscriber list, and dynamic email templates.

Mail Sending API perks over SMTP in Ruby on Rails using MailGun or SendGrid

Mail sending in Ruby on Rails is simple method of SMTP settings. Just configure the SMTP settings available here: https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration.

The problem with SMTP is that you as ROR developer has to handle all about sending the emails from the application. There is also much less chance of delivery than the APIs. Furthermore, many APIs give many perks for developers to ease their life.

MailGun:

MailGun is one such API that also provide SMTP, but the API has many more features included.

For Ruby and Rails, MailGun has its gem available here.

Instead of SMTP, just add gem into rails and add the api key of mailgun account. And this will give at least more probable chance of delivery of email than SMTP.

config/environments/production.rb:

config.action_mailer.default_url_options = {host: "xxxxxxxxxx"}
  config.action_mailer.perform_deliveries = true
  config.action_mailer.delivery_method = :mailgun
  config.action_mailer.mailgun_settings = {
      api_key: Rails.application.credentials.MAILGUN[:api_key],
      domain: 'xxxxxxxxxx',
      api_host: 'api.eu.mailgun.net' # Uncomment this line for EU region domains
  }

Apart from sending the email, you can also get the stats about the sent emails in the application as well if this is the requirement in the application.

SendGrid:

SendGrid APIs provide much more functionality than mailgun.

For Ruby on Rails, SendGrid has its gem available here.

Newsletter Subscription

SendGrid has marketing solution, where we can create a subscriber list and send the marketing emails apart from just transactional emails.

So, using the same gem when a user signs in the application you can ask if it wants newsletter subscription then you can add to the list in sendgrid. So, to add to subscriber list a user call this job in user after create callback:

app/jobs/add_user_to_sendgrid_list_job:

class AddUserToSendgridListJob < ApplicationJob
  require 'sendgrid-ruby'
  include SendGrid
  queue_as :default

  LIST_ID = 'abcdnbh-hbdfehbfjhbe-hbhefb'.freeze

  def perform(user_id)
    user = User.kept.find_by(id: user_id)
    if user
      # Add the user data
      user_data = [{ email: user.email, first_name: user.name }]
      # Add to list
      list_ids = [WALLET_LIST_ID]
      body = { list_ids: list_ids, contacts: user_data }
      sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
      response = sg.client.marketing.contacts.put(request_body: body)
      # If not added then send error to sentry
      unless ['202'].include? response.status_code
        # Generate Error Here
      end
      response.parsed_body
    end
  end
end

This will add the user to your marketing list as well.

Email Templates:

SendGrid also gives Dynamic Email Templates for us developers so that we don’t have to convert the HTML template to erb for rails. Moreover, we don’t have to update every-time client asks us to update the template as because then client has to update the html in sendgrid, and we don’t have to do anything.

So to send an email through rails, you can user this job app/jobs/email_job.rb:

require "sendgrid-ruby"

class EmailJob
  include Sidekiq::Worker
  include SendGrid
  sidekiq_options queue: 'default', retry: 3

  NOREPLY_FROM_EMAIL = "hello@world.com".freeze
  NOREPLY_FROM_NAME = "Hello World"

  def perform(user_id, subsitutions, template_id)
    sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
    user = User.kept.find_by(id: user_id)
    if user
      data = {
        "personalizations": [{
                               "to": [{
                                        "email": user.email,
                                        "name": user.name
                                      }],
                               "dynamic_template_data": subsitutions
                             }],
        "from": {
          "email": NOREPLY_FROM_EMAIL,
          "name": NOREPLY_FROM_NAME
        },
        "template_id": template_id
      }
      response = sg.client.mail._("send").post(request_body: data)
      unless ['200', '201', '202'].include? response.status_code
        # Generate Error Here
      end
    end
  end
end

Substitutions are the place where we will substitute user characteristics like name, link etc.

This job can be called as:

EmailJob.perform_async(id, { confirm_url: url, name: name }, ENV['CONFIRM_EMAIL_TEMPLATE'])

so, when email is sent then confirm_url and name in email is substituted with provided data.


Conclusion:

So, APIs providing email clients give more chance of email delivery with API than SMTP. Also, MailGun and SendGrid provide more good features using APIs. So please try them one time with API.