What email verification is and why products use it
When you sign up for a web application, you're usually asked to verify your email address before getting full access. This isn't just a formality — it serves several real purposes.
Why apps require email verification:
- Confirms the email address actually belongs to you
- Prevents people from signing up with someone else's email
- Establishes a working communication channel before the account is active
- Reduces spam accounts and bot registrations
- Ensures password reset and important notifications can reach the user
The flow is almost always the same: you enter your email, the server generates a unique one-time token, embeds it in a link, sends it to your inbox, and waits for you to click it. When you click the link, the server validates the token, marks the email as verified, and logs you in.
How the email verification flow works step by step
Here is the typical lifecycle of an email verification:
1. User submits signup form
The server receives email and password. It creates a new user account in the database and sets a flag like requiresEmailVerification: true. The account exists but isn't active yet.
2. Server generates a verification token
A cryptographically random token is created — usually 32–64 bytes of randomness, encoded as hex or base64. This token is hashed before storage (so the database never holds the raw value), and given an expiry time, typically 24 hours.
3. Verification email is sent
The server calls an email provider (like Resend, SendGrid, or AWS SES) with a link in the format:
https://yourapp.com/api/auth/verify-email?token=abc123...The email provider delivers the message to the user's inbox.
4. User clicks the link
The browser hits your server with the token in the URL. The server:
- Looks up the token (by hashing the incoming value and matching against stored hashes)
- Checks it hasn't expired
- Checks it hasn't already been used
- Marks the token as used
- Updates the user:
emailVerifiedAt = now,requiresEmailVerification = false - Creates a session and logs the user in
- Redirects to the application
5. Token is invalidated
Once used, the token can never be used again. If the user requests another verification email, the old tokens are invalidated and a new one is issued.
One-time tokens are critical. A verification token should only work once. If you click the same link twice, the second click should fail. This prevents replay attacks and ensures each email gets verified exactly once.
Why verification emails land in spam
This is the most common complaint with transactional email. The email was sent successfully (the API returned 200 OK), but it never appeared in the user's inbox — or worse, arrived in the Spam folder.
There are several reasons this happens.
Missing DNS authentication records
This is the most common cause. Email providers and spam filters check whether the sending server is authorized to send email on behalf of the domain. If the DNS records (SPF, DKIM, DMARC) are missing or misconfigured, many filters will reject or quarantine the message.
Sending from a shared or untrusted domain
Many email providers (including Resend) offer a default sending domain for testing — something like onboarding@resend.dev. This domain is shared by thousands of developers, and its reputation is mixed. Emails from shared domains frequently land in spam.
The fix is always to use your own domain.
New domain with no sending history
Email spam filters consider domain age and sending history. A brand new domain that suddenly starts sending thousands of emails looks suspicious. This reputation builds over time and through proper authentication.
Content that triggers spam filters
Certain patterns in email content trigger filters: all-caps subject lines, excessive links, suspicious phrases, HTML with hidden elements, or a very low text-to-image ratio.
No unsubscribe header for marketing emails
For marketing emails, the absence of a List-Unsubscribe header is a strong spam signal. For transactional email (verification, password reset), this is less critical — but for newsletters or promotional content it's mandatory.
Understanding SPF, DKIM, and DMARC
These three DNS-based systems form the foundation of email authentication. Together they tell receiving mail servers: "this message really came from who it claims to be from."
SPF — Sender Policy Framework
SPF is a DNS record that lists which mail servers are allowed to send email on behalf of your domain.
When Gmail receives an email claiming to be from noreply@yourdomain.com, it checks the DNS of yourdomain.com for an SPF record and asks: "Is the server that sent this email on the approved list?"
How to set it up:
Add a TXT record to your domain's DNS at the root (@):
v=spf1 include:amazonses.com ~allIf you're using Resend, the value they give you looks like:
v=spf1 include:_spf.resend.com ~allThe ~all at the end means "soft fail" — emails from unlisted servers will be marked suspicious but not outright rejected. Using -all (hard fail) is stricter and rejects them entirely.
You can only have one SPF record per domain. If you already have one, don't add a second — merge the include: statements into a single record: `` v=spf1 include:_spf.google.com include:_spf.resend.com ~all ``
DKIM — DomainKeys Identified Mail
DKIM adds a cryptographic signature to every outgoing email. The sending server signs the message with a private key, and the receiving server verifies it using a public key published in your DNS.
This proves two things: the email came from your server, and the content wasn't tampered with in transit.
How to set it up:
Your email provider generates a key pair. You publish the public key as a DNS TXT record. The format is:
Name: resend._domainkey.yourdomain.com
Type: TXT
Value: v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4G...The exact name and value are provided by your email provider in their domain setup flow. You copy them into your DNS exactly as shown.
DKIM records can take up to 48 hours to propagate, though usually it's under an hour.
DMARC — Domain-based Message Authentication, Reporting, and Conformance
DMARC builds on SPF and DKIM by telling receiving servers what to do when those checks fail. It also gives you visibility through aggregate reports sent to your email address.
A basic DMARC record:
Name: _dmarc.yourdomain.com
Type: TXT
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.comThe p= parameter controls the policy:
| Policy | Meaning |
|---|---|
p=none | Monitor only — don't reject anything, just send reports |
p=quarantine | Suspicious emails go to spam |
p=reject | Failing emails are rejected entirely |
Start with p=none while you're getting set up. This lets you receive reports without risking legitimate mail being dropped. Once you've confirmed your SPF and DKIM are working correctly, move to p=quarantine and eventually p=reject.
Setting up a custom sending domain step by step
Here is the full process for configuring a custom domain with a transactional email provider.
Step 1: Add your domain in the provider dashboard
Log in to your email provider (Resend, SendGrid, Postmark, etc.) and navigate to Domains. Add your domain — for example yourdomain.com. The provider will show you a list of DNS records to add.
Step 2: Add the DNS records
Go to your DNS provider (Cloudflare, Vercel, Namecheap, Route 53, etc.) and add each record exactly as shown:
- One
TXTrecord for SPF (at@or root) - One
TXTrecord for DKIM (at a name likeresend._domainkey) - One
TXTrecord for DMARC (at_dmarc)
Step 3: Verify in the dashboard
Return to your email provider and click "Verify" or "Check DNS". The provider will query your DNS and confirm each record is present and correct.
DNS changes can take anywhere from a few minutes to 48 hours to propagate globally. If verification fails immediately after adding the records, wait 10–30 minutes and try again.
Step 4: Update your sending address
Change the from address in your application to use your verified domain:
From: PromptPlan <noreply@yourdomain.com>Never send from onboarding@resend.dev or similar provider default addresses in production.
Step 5: Send a test email
Send a test email to your own inbox and check that it arrives without spam warnings. Check the email headers (most email clients let you view raw headers) to confirm the DKIM signature is present and the SPF check passed.
How to check if your email is configured correctly
Several free tools can analyze your email configuration and tell you exactly what's wrong:
MX Toolbox — Check your SPF, DKIM, and DMARC records without sending anything. Enter your domain at mxtoolbox.com.
Mail Tester — Send a test email to a temporary address they give you, and receive a detailed spam score with line-by-line analysis of what's wrong. Visit mail-tester.com.
Google Postmaster Tools — If you send significant volume to Gmail addresses, Google's Postmaster Tools shows your domain reputation, spam rate, and authentication success rates. Free to set up at postmaster.google.com.
Provider dashboard — Your email provider's dashboard usually shows delivery status for each email: delivered, bounced, or marked as spam. For Resend, check the Emails tab and look at the providerMessageId to trace individual messages.
Common problems and how to fix them
"I added SPF but emails still go to spam"
SPF alone is not enough. Spam filters increasingly require all three: SPF, DKIM, and DMARC. Add DKIM and DMARC as well.
"Verification failed after adding DNS records"
DNS propagation takes time. Wait 15–30 minutes and try again. If it still fails after an hour, double-check the record names and values — a single extra character or wrong subdomain will break it.
"I have two SPF records and verification fails"
Merge them into one. DNS allows only one SPF TXT record at the root. Combine multiple include: statements into a single record.
"Email arrives but the link is expired"
Token expiry is typically 24 hours. If the user waited too long, they need to request a new link. Make sure your verification page has a clear option to resend the email.
"Email arrives in Gmail's Promotions tab"
This is not spam — it's a categorization choice by Gmail. For transactional email, include a clear preheader, avoid promotional language, and make sure the from name is recognizable. Some users may need to drag the email to Primary once, which trains Gmail for future messages.
"The email was 'delivered' according to the provider but never arrived"
The provider marked it delivered when the receiving server accepted it — but the receiving server may have moved it to spam internally. Check the spam folder. If it's consistently missing, run a test through Mail Tester to identify the specific spam trigger.
Summary
Email verification is a standard security pattern: the server sends a one-time link to confirm ownership of the address, and clicking it activates the account. The flow is straightforward — the hard part is making sure the email actually arrives.
To ensure reliable delivery:
- Use a custom domain — never send from a shared provider domain in production
- Configure SPF to authorize your mail server
- Configure DKIM to cryptographically sign your messages
- Configure DMARC to set a policy and receive reports
- Use a trusted transactional email provider (Resend, Postmark, SendGrid)
- Test with Mail Tester and monitor with your provider dashboard
Most spam problems come down to missing DNS records. Once SPF, DKIM, and DMARC are all passing, the vast majority of deliverability issues disappear.