Home Posts Post Search Tag Search

Domains and Email - 01 - Setting Things Up
Published on: 2026-04-10 Tags: elixir, Blog, Side Project, LiveView, Game Site, Resend, Namecheap

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:

  1. Buy a domain
  2. Add it to your email provider
  3. Add DKIM + SPF + MX records to DNS
  4. Wait for verification
  5. 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.