$How I Set Up Email on My Custom Domain for Free
A complete, beginner-friendly walkthrough of how I wired up contact@parish.cv to receive mail in my regular Gmail inbox and send replies that look like they came from my own domain — without paying for Google Workspace. Free tier, three providers, around 30 minutes.
I own the domain parish.cv and I wanted a proper email address on it — contact@parish.cv — so I could put it on my resume and website without using a free @gmail.com address.
The "official" way to do this is Google Workspace, which costs around $7/month per user. I didn't want to pay that. So I built a free version using three services that each do one thing well:
| Service | What it does | Cost |
|---|---|---|
| Cloudflare Email Routing | Receives mail at contact@parish.cv and forwards it to my Gmail | Free, unlimited |
| Resend | Sends mail out (so replies look like they came from my domain) | Free up to 100/day, 3000/month |
| Gmail | The mailbox and the interface I already use every day | Free |
The end result: I read and reply to contact@parish.cv from my normal Gmail account, and recipients see Parish <contact@parish.cv> — never my real Gmail address.
This post is the full step-by-step. If you have a domain you bought from somewhere (Namecheap, Porkbun, Cloudflare Registrar, anywhere) and an account on Cloudflare, you can copy this exactly. I'll explain why each step exists, not just what to click.
How the pieces fit together
Email is two completely separate problems: receiving mail and sending mail. Most beginners (myself included, at first) assume one service does both. It does not.
Receiving mail:
someone@anywhere.com
→ DNS MX record points to Cloudflare
→ Cloudflare Email Routing catches it
→ forwards to my-real-inbox@gmail.com
Sending mail:
I hit "Send" in Gmail with From: contact@parish.cv
→ Gmail connects to smtp.resend.com on port 587 (TLS)
→ Resend signs it with DKIM and ships it
→ recipient sees it land from parish.cv, not gmail.com
Cloudflare can receive but it cannot send (it has no outbound SMTP). Resend can send but it doesn't run inboxes. Gmail can do both but won't touch your custom domain unless you pay for Workspace. So we glue them together.
One quirk you'll see below: Resend puts its DNS records on a subdomain (send.parish.cv) instead of the apex domain (parish.cv). That's deliberate — it stops Resend's anti-spam records from fighting with Cloudflare's. You'll see why in Step 2.
Let's go.
Step 1 — Cloudflare Email Routing (inbound)
This is the easy half. Cloudflare will catch any mail sent to your domain and forward it wherever you want.
Open the dashboard → click your domain → in the left sidebar click Email → Email Routing.
If this is the first time, click Get started. Cloudflare will offer to write the required DNS records automatically — say yes. It adds three MX records and a few TXT records to your zone. They look like this:
Type Name Content Priority
MX parish.cv route1.mx.cloudflare.net 88
MX parish.cv route2.mx.cloudflare.net 19
MX parish.cv route3.mx.cloudflare.net 72
TXT parish.cv v=spf1 include:_spf.mx.cloudflare.net ~all
TXT cf2024-1._domainkey.parish.cv v=DKIM1; h=sha256; ...
Don't touch these by hand later. Cloudflare manages them.
Add a destination address. This is where forwarded mail will land. Click Destination addresses → Add destination address → type your real Gmail address (e.g. you@gmail.com). Cloudflare sends a one-click verification email to that Gmail. Click the link. You'll see "Verified" appear.
Create the forwarding rule. Click Routing rules → Create address:
- Custom address:
contact(the part before the@) - Action: Send to an email
- Destination: pick your verified Gmail
Save. Status flips to Active.
That's it. Send a test mail from your phone to contact@parish.cv and it'll appear in your Gmail within seconds. Receiving is done.
Step 2 — Resend (outbound SMTP)
Now the harder half: making Gmail send as contact@parish.cv instead of as your real Gmail address.
Gmail's compose window has a feature called Send mail as, which lets you plug in any SMTP server. We need an SMTP server that owns the domain. That's where Resend comes in.
Sign up at resend.com — free, no credit card. Then:
Add your domain. Dashboard → Domains → Add Domain → type parish.cv (no www, no subdomain) → pick a region close to you. I picked Tokyo (ap-northeast-1) because I'm in Asia. Pick whichever is geographically nearest — it doesn't affect delivery, but it's the region your mail will leave from.
Auto-configure with Cloudflare. If your DNS is on Cloudflare (it is, that's how Step 1 worked), Resend offers a one-click "Auto configure" button. Authorize it. Resend will write three records into your Cloudflare zone:
Type Name Content Priority
TXT resend._domainkey p=MIGfMA0GCSqGSIb3D... (DKIM public key)
MX send feedback-smtp.ap-northeast-1.amazonses.com 10
TXT send v=spf1 include:amazonses.com ~all
Important detail about that send subdomain. Notice that the MX and SPF records go on send.parish.cv, not on parish.cv itself. This is the trick that makes Cloudflare and Resend coexist.
SPF (Sender Policy Framework) is a TXT record that says "these servers are allowed to send mail as me." You can only have one SPF record per name. The apex parish.cv already has Cloudflare's SPF on it (include:_spf.mx.cloudflare.net). If we tried to add Resend's SPF on the apex too, we'd either overwrite Cloudflare's or have to merge them — and either way, debugging gets ugly.
By scoping Resend to the send subdomain, both SPF records live happily side by side. The actual envelope-from address on outgoing mail becomes something like bounces@send.parish.cv, which is fine — recipients never see it. The visible From header is still contact@parish.cv. Best of both worlds.
After the records propagate (usually 30 seconds with Cloudflare), the domain in Resend flips to Verified with a green check.
Create an API key. This is what Gmail will use as the SMTP password.
Dashboard → API keys → Create API Key:
- Name:
gmail-smtp-parishcv(anything descriptive) - Permission: Sending access
- Domain:
parish.cv
Click create. You'll see a key that starts with re_… — this is shown exactly once. Copy it now. Paste it somewhere safe (a password manager is ideal). If you lose it, you have to make a new one.
I also dropped mine in my project's .env.local for any future server-side sending:
# .env.local (never commit this file)
RESEND_API_KEY=re_your_key_here
(Make sure .env.local is in your .gitignore. Never commit API keys.)
Step 3 — Gmail "Send mail as"
Now we wire the Resend API key into Gmail as an SMTP password.
If you only have one Gmail account, just go to Gmail settings. If you have multiple Google accounts signed in, swap the number in https://mail.google.com/mail/u/<N>/ to the index of the profile you want to use (the first signed-in account is 0, the second is 1, and so on).
Click the gear ⚙️ → See all settings → tab Accounts and Import → row Send mail as → Add another email address.
A small dialog opens.
Page 1 of the dialog:
- Name:
Parish(whatever you want recipients to see) - Email address:
contact@parish.cv - Uncheck "Treat as an alias"
That checkbox is subtle but important. Leaving it checked makes Gmail forge the From header while still sending through Google's own SMTP servers — which works for a day or two and then Gmail starts injecting "via gmail.com" or routing replies to your real address. Unchecking it forces Gmail to use the SMTP server we're about to give it, the way it's supposed to.
Click Next Step.
Page 2 — SMTP details:
| Field | Value |
|---|---|
| SMTP Server | smtp.resend.com |
| Port | 587 |
| Username | resend |
| Password | the re_... API key from Step 2 |
| Secured connection | TLS |
Click Add Account.
Gmail now sends a verification email to contact@parish.cv. This is the moment the whole setup gets tested in one shot:
- Gmail's email leaves Google going to
contact@parish.cv - Cloudflare Email Routing's MX records catch it (because of Step 1)
- Cloudflare forwards it to my real Gmail inbox
- I click the verification link inside that email
If any of Step 1's DNS records are wrong, the link never arrives. When it does arrive, you click it, and Gmail flips the new send-as alias to verified.
One last setting. Back in Settings → Accounts and Import → When replying to a message → choose Reply from the same address the message was sent to. This makes replies to contact@parish.cv mail go out as contact@parish.cv automatically. Without this, every reply defaults to your real Gmail address — defeating the whole point.
Step 4 — DMARC (optional but recommended)
DMARC is a policy record that tells receiving mail servers what to do when a message fails SPF or DKIM checks. It also gives you daily reports about who's sending mail as you.
You don't strictly need this to make mail work. But you do need it if you want your mail to land in inboxes instead of spam folders, especially at strict providers like Gmail and Microsoft.
Add one more TXT record in Cloudflare DNS:
Type Name Content
TXT _dmarc v=DMARC1; p=none; rua=mailto:your-email@gmail.com
Breaking down the policy string:
v=DMARC1— versionp=none— "don't actually block anything yet, just observe"rua=mailto:...— send aggregate reports to this address daily
Starting at p=none is the safe default. After a week or two of clean reports landing in your inbox (Gmail providers, Microsoft, Yahoo, etc. will all send you XML reports), you can tighten it:
p=none→ just monitorp=quarantine→ suspicious mail goes to spamp=reject→ suspicious mail gets bounced
Only tighten once you're confident no legitimate sender is failing. Otherwise you'll accidentally block your own forgotten newsletter or invoicing service.
The complete DNS record list
After all four steps, this is everything in my Cloudflare DNS zone related to email:
Type Name Content Priority
MX parish.cv route1.mx.cloudflare.net 88
MX parish.cv route2.mx.cloudflare.net 19
MX parish.cv route3.mx.cloudflare.net 72
TXT parish.cv v=spf1 include:_spf.mx.cloudflare.net ~all
TXT cf2024-1._domainkey.parish.cv v=DKIM1; h=sha256; k=rsa; ... (Cloudflare DKIM)
TXT resend._domainkey.parish.cv p=MIGfMA0GCSqGSIb3D... (Resend DKIM)
MX send.parish.cv feedback-smtp.ap-northeast-1.amazonses.com 10
TXT send.parish.cv v=spf1 include:amazonses.com ~all
TXT _dmarc.parish.cv v=DMARC1; p=none; rua=mailto:you@gmail.com
All Resend records are set to DNS-only (the gray cloud icon in Cloudflare, not the orange one). DNS records don't need Cloudflare's proxy — that's for HTTP traffic only. If you accidentally set them to proxied (orange cloud), email will silently break.
How I verified it actually works
Three checks, all done in five minutes after finishing Step 3:
1. Send a test email. In Gmail, hit Compose. Click the From dropdown — Parish <contact@parish.cv> is now an option. Pick it. Send to a test address.
2. Inspect the headers. Open the test email in the recipient's inbox → "Show original" (Gmail) or "View source." Look for these lines:
Authentication-Results: mx.google.com;
dkim=pass header.i=@parish.cv
spf=pass smtp.mailfrom=send.parish.cv
dmarc=pass header.from=parish.cv
All three pass. That's the green light.
3. Check Resend logs. Resend dashboard → Logs. Your test should appear as POST /emails 200. If it doesn't, Gmail didn't actually use Resend — go re-check the "Uncheck Treat as an alias" step.
Things to know before you ship this
Free tier ceilings. Resend gives 100 emails/day and 3000/month free. For personal use this is way more than enough. If you go viral, you pay a few dollars to upgrade.
Bounces and complaints. When a recipient marks you as spam or your mail bounces, you'll see it in Resend → Logs. The Amazon SES return-path on send.parish.cv is what captures these. Worth checking once a month.
Rotating the SMTP password. If you ever leak the API key:
- Create a new key in Resend
- In Gmail: Accounts and Import → Send mail as → edit info → update the password
- Revoke the old key in Resend
- Update
.env.localif you use it server-side
Do it in that order so you're never without a working key.
Region matters. I picked Tokyo. Every Resend DNS record encodes that region (ap-northeast-1.amazonses.com). If you decide to change region later, the DNS records have to be regenerated. Pick once, stick with it.
Don't add another SPF record on the apex. This is the most common way people break this setup. If you sign up for another sending service later (Mailgun, Postmark, anything) and it tries to add v=spf1 include:... on the apex, refuse. Either nest it under a different subdomain like Resend does, or merge it into the existing Cloudflare SPF record — never have two.
Why I like this setup
- It's free, forever, within the limits I'll never hit
- No vendor lock-in: each piece is replaceable independently
- My existing Gmail keyboard shortcuts, search, filters, labels all still work — it's just Gmail with a different From address
- DKIM-signed and DMARC-aligned, so it lands in inboxes, not spam
- 30 minutes from start to first email
If you've been putting off setting up a "real" email address for your domain because Workspace is too expensive, this is the answer. Go do it.
If you have questions or get stuck on any step, you can — appropriately enough — email me at contact@parish.cv.