Today I wanted to integrate AWS SES with my Rails app. I am currently migrating fastretro.app from Laravel to Rails. If you are interested in sending emails with SES here is a step-by-step guide to integrate AWS SES into your Rails app.
Step 1: Add the Gems
Open your Gemfile and add the required gems:
# Gemfile
gem 'aws-sdk-rails', '~> 5'
gem 'aws-actionmailer-ses', '~> 1'Run the installation command in your terminal:
bundle installStep 2: Configure ActionMailer
You need to tell Rails to use SES instead of the default SMTP.
Open config/environments/production.rb (and development.rb if you want to test locally) and add:
# config/environments/production.rb
Rails.application.configure do
# ... existing config ...
# AWS SES
config.action_mailer.delivery_method = :ses_v2
config.action_mailer.ses_v2_settings = { region: 'eu-central-1' }
endStep 3: Get your Access Keys (IAM)
Next we need to get our AWS credentials so our Rails app can connect to AWS.
- Go to the AWS Console and search for "IAM" (Identity and Access Management).
- Click Users -> Create user.
- Name:
rails-ses-mailer(or similar). - Permissions: Select "Attach policies directly".
- Search for
AmazonSESFullAccess(or for better security, create a custom policy that only allowsses:SendEmailandses:SendRawEmail). Select it and click Next -> Create user. - Click on the newly created user name in the list.
- Go to the Security credentials tab.
- Scroll down to Access keys and click Create access key.
- Select Application running outside AWS (or "Local code"), then click Next/Create.
- Copy the Access Key ID and Secret Access Key. (Save them! You won't see the secret again).
Hint: If you want to use a custom policy instead of AmazonSESFullAccess, here is the one I used:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}Step 4: Add Credentials to Rails
The safest way to store these is in your Rails Credentials or Environment Variables.
Option A: Using Environment Variables (Recommended for Heroku/Docker)
Add these to your .env file or your server's environment config:
AWS_ACCESS_KEY_ID=AKIA......
AWS_SECRET_ACCESS_KEY=abcde12345......
AWS_REGION=eu-west-1The AWS SDK automatically looks for these specific variable names, so you don't need to write any extra code to load them.
Option B: Using Rails Credentials
Run EDITOR="code --wait" rails credentials:edit and add:
aws:
access_key_id: "AKIA..."
secret_access_key: "abc..."Step 5: Update your Mailer from address
Make sure your Mailers use a domain you have verified in SES.
# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: "[email protected]" # Must match your verified domain
layout "mailer"
endHow to Test it Immediately (Rails Console)
You can test the entire setup directly from your terminal without building a form.
- Run
rails console - Create a test mailer and send:
class ConsoleTestMailer < ActionMailer::Base
def test_email
mail(
from: "[email protected]",
to: "[email protected]",
subject: "Hello from Rails & SES",
body: "This is a test email sent securely via AWS SDK."
)
end
end
ConsoleTestMailer.test_email.deliver_now!Important: Use deliver_now! (with the bang !) instead of deliver_now. The version without ! silently swallows errors, so your email might fail without you knowing. With deliver_now!, any delivery errors will be raised as exceptions.
If it returns a <Mail::Message> object with "Delivered mail" in the output, check your inbox! If you don't see it, check your spam folder or read the troubleshooting section below, because I had an issue where ActionMailer said "Delivered" and I got the <Mail::Message> response but the email never arrived.
Troubleshooting
"Invalid delivery method :ses"
Make sure you restarted the Rails console after running bundle install.
Emails show "Delivered" but never arrive
If your console shows "Delivered mail" but you don't receive the email (and it's not in spam), the error might be getting swallowed silently. Always use deliver_now! to see actual errors.
SSL Certificate Error on macOS (Ruby 3.4+ / OpenSSL 3.6+)
If you see an error like:
SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get certificate CRL)This is a known issue with Ruby 3.4+ and OpenSSL 3.6 on macOS. The fix is simple - add the openssl gem explicitly to your Gemfile:
# Gemfile
gem 'openssl'Then run bundle install and restart your Rails console. This forces Bundler to use a compatible version of the OpenSSL gem that doesn't have the CRL (Certificate Revocation List) verification issue.
See GitHub Issue #55886 for more details.
Next Steps
Once you confirm the test email works, you are technically live!
Important: Make sure to check if you are still in the AWS SES Sandbox. In sandbox mode, you can only send emails to addresses you have manually verified in the SES console. To email real customers, you must request "Production Access" from AWS.
Also remember to:
- Verify your sending domain in SES
- Set up SPF, DKIM, and DMARC records for better deliverability
- Monitor your SES sending statistics and bounce rates