We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Here’s a clean, corrected, and slightly upgraded version you can drop straight into your blog:
Sending Real Emails in Phoenix with Resend (Custom Domain Setup)
One thing that makes a project feel “real” is sending actual emails—especially for account verification and password resets.
I recently set this up for my Phoenix app, and while it’s not complicated, there are a few confusing steps (mostly around DNS). Here’s the exact process I followed.
Step 1: Buy a Domain
I bought a domain through Namecheap. You don’t need anything fancy—just something you can reuse across projects.
Example:
testsites.com
The important part is that you control the DNS settings.
Step 2: Add the Domain to an Email Provider
I used Resend as the email provider.
After adding the domain in Resend, it generated a set of DNS records that needed to be added to my domain.
Step 3: Configure DNS (This Is the Tricky Part)
In Namecheap, under Advanced DNS, I added the following records.
DKIM Record
DKIM allows your emails to be cryptographically signed so receiving servers can verify they were sent by an authorized source.
- Type: TXT
- Host:
resend._domainkey
- Value:
p=... (long key provided by Resend)
SPF Record (for sending subdomain)
This tells email providers which services are allowed to send emails from your domain.
- Type: TXT
- Host:
send
- Value:
v=spf1 include:amazonses.com ~all
MX Record (Required for Resend)
This is used by Resend’s infrastructure to handle delivery feedback.
- Type: MX
- Host:
send
- Value:
feedback-smtp.us-east-1.amazonses.com
- Priority:
10
Step 4: Wait for DNS Propagation
After saving the records, it took a few minutes for them to become visible publicly.
Resend then verified:
- DKIM ✅
- SPF ✅
- Domain ✅
Step 5: Configure Phoenix to Send Emails
With the domain verified, I configured my app to send emails using Swoosh.
Dependencies
defp deps do
[
{:swoosh, "~> 1.5"},
{:finch, "~> 0.13"},
{:resend, "~> 0.4"}
]
end
Mailer Module
defmodule GameSite.Mailer do
use Swoosh.Mailer, otp_app: :game_site
end
Dev Config
# config/dev.exs
config :game_site, GameSite.Mailer,
adapter: Resend.Swoosh.Adapter,
api_key: System.get_env("RESEND_API_KEY")
Later, you can move this to runtime.exs for production.
Step 6: Send a Test Email
Before starting IEx, create an API key in Resend and export it:
export RESEND_API_KEY=your_key
Then:
iex -S mix
Application.get_env(:game_site, GameSite.Mailer)
(
import Swoosh.Email
email =
new()
|> to("your_real_email@gmail.com")
|> from({"GameSite", "no-reply@adamsites.com"})
|> subject("GameSite test")
|> text_body("Test email from GameSite")
GameSite.Mailer.deliver(email)
)
You should now receive the email.
Common Gotchas
1. Wrong Adapter
If you see:
Swoosh.Adapters.Local
You are not sending real emails—only previewing them locally.
Make sure you’re using:
Resend.Swoosh.Adapter
2. DNS UI Confusion
Make sure you’re editing:
- Advanced DNS
Not:
- Redirects
- Email forwarding
3. Missing Records
If your domain won’t verify, double-check:
- DKIM exists
- SPF exists
- MX exists
Providers like Resend rely on these records. If any are missing, verification will fail.
4. Underlying Infrastructure
Some providers (like Resend) use underlying infrastructure such as Amazon SES.
If they provide SPF or MX records, you must add them exactly as shown or the domain will not verify.
Using a Subdomain (Recommended)
Instead of sending from your root domain, you can use a subdomain like:
no-reply@send.yourdomain.com
This keeps email-related DNS (SPF, MX, etc.) isolated from your main domain.
Summary
To send emails from your app:
- Buy a domain
- Add it to your email provider
- Add DKIM + SPF + MX records to DNS
- Wait for verification
- Send emails from your app
Once this is set up, adding features like email verification and password resets becomes straightforward.
This was one of those small steps that makes the whole application feel more complete.