Workshop tickets on sale now: Engineering better hiring practices

SendGrid on Heroku in 2021

In the end of 2020 SendGrid required customers to enable two-factor authentication, which means they stopped accepting SMTP requests made with username and password via Basic Authentication. This is better for security since providing account username and password for authenticating against the SendGrid SMTP API gives full access to your SendGrid account, and therefore it is a security risk if these credentials get compromised. Using API Keys adds an additional layer of security, and is the recommended way to securely talk to SendGrid APIs.

This means that by default the behaviour of the Twilio SendGrid addon may be somewhat unexpected. It still automatically adds a SENDGRID_USERNAME and SENDGRID_PASSWORD to your app's environment variables, but sending emails straight out of the box will no longer work.

There's a simple workaround. You will need to log into your Twilio SendGrid account and:

  1. Generate an API key under "Settings" > "API Keys". Give it a name, and select "Restricted Access". Restricted Access is recommended as it customises levels of access for all parts of your account.
  2. To send email only, your API key will require "Mail Send" > "Full Access permissions".
  3. To use your API key with the SMTP integration, set your username to be "apikey". Your password will be the API key you generated in the previous step.

In my Environment variables I use the following values:

SMTP_USERNAME: "apikey"
SMTP_PASSWORD: <Generated API Key starts with SG.>
SMTP_AUTHENTICATION: "plain"
SMTP_ADDRESS: smtp.sendgrid.net
SMTP_PORT: 587

Then in my Rails app, I have the following setup:

# config/smtp.rb
SMTP_SETTINGS = {
  address: ENV.fetch("SMTP_ADDRESS"),
  authentication: ENV.fetch("SMTP_AUTHENTICATION", "plain"),
  domain: ENV.fetch("SMTP_DOMAIN"),
  enable_starttls_auto: true,
  password: ENV.fetch("SMTP_PASSWORD"),
  port: ENV.fetch("SMTP_PORT", "587"),
  user_name: ENV.fetch("SMTP_USERNAME"),
}.freeze

# config/environments/production.rb
require Rails.root.join("config/smtp")

Rails.application.configure do
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = SMTP_SETTINGS
end

# app.json
{
  # ..
  "env": {
    "SMTP_ADDRESS": {
      "required": true
    },
    "SMTP_DOMAIN": {
      "required": true
    },
    "SMTP_PASSWORD": {
      "required": true
    },
    "SMTP_USERNAME": {
      "required": true
    }
  },
}

Working all this out required a number of conversations with both Twilio and Heroku support. Considering that this change is required for new and old SendGrid clients, I would expected Heroku support to be on top of this, and that the documentation would be more upfront. In any case, here are a few more references:

Posted on February 17, 2021 by Elle Meredith

Receive monthly updates

Our Australian residents live on, and benefit from, the colonised lands of the Boon Wurrung, the Wurundjeri, and the Darkinjung. We acknowledge the Traditional Owners and Custodians of these lands and recognise their enduring connection to land, waters, and culture. We pay our respects to their elders, past and present.

We are grateful we share this land today. We hold sorrow for the costs of that sharing, and we hope for a reconciliation to bring us to a state of equity, justice, and partnership together.