Why Transactional Email Is Harder Than It Looks
Every client project we build involves transactional email in some form — booking confirmations, lead intake notifications, Stripe payment receipts, form acknowledgments. And on almost every project, email deliverability requires deliberate setup before it works reliably.
The failure mode is always the same: emails go to spam, or don't arrive at all, because the sending domain isn't properly authenticated. Here's the exact configuration we use.
Step 1: Domain Authentication in SendGrid
Before sending a single email, authenticate your sending domain. In SendGrid's dashboard, go to Settings, then Sender Authentication, then Authenticate Your Domain.
This generates three DNS records: two CNAME records for DKIM (DomainKeys Identified Mail), and one CNAME record for click/open tracking (optional but recommended). Add these to your DNS provider and verify in SendGrid. Until this is done, your emails will arrive with a 'via sendgrid.net' attribution that destroys deliverability.
Step 2: SPF Record
SPF tells receiving mail servers which services are authorized to send email on behalf of your domain. Add a TXT record to your DNS:
v=spf1 include:sendgrid.net ~all
If you're also sending from Google Workspace, combine them:
v=spf1 include:sendgrid.net include:_spf.google.com ~all
Only one SPF record is allowed per domain. If you have multiple, merge them.
Step 3: DMARC Policy
DMARC ties SPF and DKIM together and tells receiving servers what to do with messages that fail authentication. Start permissive:
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com
After a week of receiving reports and confirming legitimate mail is passing, move to p=quarantine, then eventually p=reject. Skipping straight to p=reject before validating your setup will cause legitimate mail to be dropped.
Step 4: API Key Scoping
Never use a full-access SendGrid API key in production application code. Create a restricted key with only 'Mail Send' permissions. Store it in an environment variable (SENDGRID_API_KEY), never in source code.
Step 5: Suppression List Management
SendGrid maintains suppression lists for bounces, spam reports, and unsubscribes. If you're sending to a contact who previously bounced, SendGrid will silently drop the message. Check the suppression list in the dashboard if a specific recipient isn't receiving email — it's almost always the answer.
The Integration Pattern We Use
In a Next.js App Router project, transactional email lives in a route handler at app/api/contact/route.ts. The handler imports the SendGrid SDK, sets the API key from an environment variable, and calls sgMail.send() with a structured message object. The 'from' address must match your authenticated domain — mismatches are the second most common cause of deliverability failures after missing DKIM records.
Need help wiring up transactional email for a client project? Reach out at /contact.