SendGrid Domain Auth: What Actually Gets You to the Inbox
SendGrid's domain authentication isn't just a checkbox — get it wrong and your transactional email quietly rots in spam. Here's what I've learned the hard way.
The first time a client called me to say their password reset emails weren't arriving, I assumed it was a SendGrid outage. It wasn't. The emails were sending fine — they were just landing in Gmail's spam folder for every single recipient. The domain authentication was half-done, SPF was misconfigured, and nobody had noticed for three weeks because nobody checks their spam folder until they're locked out of something important.
Domain authentication in SendGrid sounds like a five-minute DNS task. It's not. There are enough moving pieces that you can have it "mostly right" and still lose 20% of your email to spam. Here's what I've figured out after setting this up for a dozen clients across healthcare, e-commerce, and SaaS.
What Domain Authentication Actually Does
SendGrid needs to send email on your behalf from your domain. Without authentication, the receiving mail server sees an email claiming to be from you@yourcompany.com but originating from SendGrid's IP space. That mismatch is a red flag — and increasingly, Gmail, Yahoo, and Microsoft treat it as one.
There are three layers here, and you need all three:
- SPF — tells receiving servers which IPs are authorized to send mail for your domain
- DKIM — cryptographically signs each message so the receiver can verify it wasn't tampered with and really came from you
- DMARC — tells receivers what to do when SPF or DKIM fail, and gives you reporting on who's sending mail as your domain
SendGrid's "domain authentication" flow sets up SPF and DKIM by having you point some CNAME records at their infrastructure. That part's straightforward. The part people skip is DMARC, and that's where things go sideways.
Setting Up Domain Authentication: The Right Way
Log into SendGrid, go to Settings → Sender Authentication → Authenticate Your Domain. Pick your DNS host, enter your domain, and SendGrid will give you a set of CNAME records to add. There are usually three: two for DKIM and one for SPF (via a CNAME to sendgrid.net).
Add all three. Verify them. That's the easy part.
Now add a DMARC record yourself — SendGrid won't do this for you. A starter record for your domain's DNS:
_dmarc.yourcompany.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@yourcompany.com; ruf=mailto:dmarc-reports@yourcompany.com; fo=1"
Start with p=none so you're in monitoring mode — you'll get reports without any mail being rejected. Once you've watched the reports for a few weeks and confirmed all your legitimate senders are passing, tighten it to p=quarantine, then eventually p=reject.
Don't skip the rua address. That's where aggregate reports go — they'll tell you if some forgotten marketing tool or legacy server is still sending mail as your domain without proper authentication.
Wiring It Into Laravel
In my projects I use Laravel's Mail facade backed by the SendGrid driver via the sendgrid/sendgrid package or just the SMTP transport with SendGrid's credentials. For most client work, SMTP is fine and keeps things simple:
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your_sendgrid_api_key
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourcompany.com
MAIL_FROM_NAME="Your Company"
Note that MAIL_USERNAME is literally the string apikey — not your account username. That tripped me up the first time.
For anything beyond basic transactional email — tracking opens/clicks, handling bounces, using dynamic templates — I'll reach for the HTTP API directly via the official SDK:
composer require sendgrid/sendgrid
<?php
use SendGrid\Mail\Mail;
class SendGridMailer
{
private \SendGrid $client;
public function __construct()
{
$this->client = new \SendGrid(config('services.sendgrid.key'));
}
public function sendTransactional(
string $toEmail,
string $toName,
string $templateId,
array $dynamicData = []
): void {
$email = new Mail();
$email->setFrom(
config('mail.from.address'),
config('mail.from.name')
);
$email->addTo($toEmail, $toName);
$email->setTemplateId($templateId);
foreach ($dynamicData as $key => $value) {
$email->addDynamicTemplateData($key, $value);
}
// Disable click tracking for transactional mail.
// Tracked links go through sendgrid.net — a shared domain.
// That's a deliverability risk you don't want.
$email->setClickTracking(false, false);
$response = $this->client->send($email);
if ($response->statusCode() >= 400) {
throw new \RuntimeException(
'SendGrid error ' . $response->statusCode() . ': ' . $response->body()
);
}
}
}
Notice setClickTracking(false, false). I'll come back to why that matters.
The Gotchas That Will Bite You
SPF flattening. SPF records have a 10 DNS lookup limit. If your domain already sends mail through G Suite, a marketing platform, a CRM, and now SendGrid, you might already be over that limit. When you go over, SPF silently fails. Use a tool like mxtoolbox.com/spf to count your lookups. If you're close, look at SPF flattening services or consolidate senders.
Link tracking and shared domains. By default, SendGrid rewrites your links to go through sendgrid.net click-tracking infrastructure. That domain is shared with thousands of other SendGrid customers, some of whom spam. If any of them land on a blocklist, your mail inherits that reputation hit. The fix is to set up link branding (also in Sender Authentication) so tracking links route through a subdomain you control — like click.yourcompany.com. And for purely transactional mail like password resets or receipts, just disable click tracking entirely. The conversion data isn't worth the risk.
The "From" domain must match your authenticated domain. If you authenticate yourcompany.com but send from noreply@mail.yourcompany.com, DMARC alignment can fail. Either authenticate the subdomain separately, or make sure you understand how SendGrid's CNAME setup aligns the signing domain with your from address. SendGrid's docs on this are okay but glossy — the actual DNS propagation and alignment behavior is worth testing explicitly with a tool like mail-tester.com before you go live.
Dedicated IPs aren't always better. SendGrid will upsell you on a dedicated IP. For high-volume senders (100k+ emails/month), that's worth it — you control your reputation. For a small client sending 2,000 emails a month, a dedicated IP with no sending history is worse than shared infrastructure. New IPs with low volume look suspicious. Shared IPs at SendGrid's scale have strong existing reputation. Know what you're buying.
Bounce handling matters for deliverability. If you ignore hard bounces and keep sending to dead addresses, your bounce rate climbs and your sender reputation drops. SendGrid tracks this for you — watch the dashboard and set up the event webhook to catch bounces and unsubscribes in your application so you stop sending to them.
// In your routes/api.php — handle SendGrid event webhooks
Route::post('/webhooks/sendgrid', function (\Illuminate\Http\Request $request) {
$events = $request->json()->all();
foreach ($events as $event) {
if (in_array($event['event'], ['bounce', 'blocked', 'invalid'])) {
// Mark the address as undeliverable in your users table
User::where('email', $event['email'])
->update(['email_deliverable' => false]);
}
}
return response('', 200);
});
You'll want to verify the webhook signature in production — SendGrid signs requests with a public key you can find in your settings. But the above captures the idea.
When I'd Reach for SendGrid
SendGrid is my default for transactional email on client projects. The API is mature, the deliverability is solid when you've configured everything correctly, the Laravel integration is painless, and the pricing is reasonable at the volumes most of my clients operate at.
I especially reach for it when a client needs:
- Dynamic transactional templates with variable substitution
- Detailed delivery event data (opens, bounces, clicks)
- Per-domain sending for multi-tenant apps
- High reliability on stuff that matters — account confirmations, order receipts, appointment reminders
I'd think twice if a client is already deep in the AWS ecosystem and needs email as part of a larger infrastructure story — SES is cheaper at scale and the IAM integration is convenient. I'd also think twice for pure marketing email at high volume, where something like Klaviyo or Mailchimp has better segmentation and list management built in. SendGrid can do marketing email, but that's not where it shines for me.
The Bottom Line
Domain authentication in SendGrid takes maybe 30 minutes to do right, but most setups I've inherited are half-done — missing DMARC, no link branding, click tracking left on for transactional mail. It's quiet failure: your emails send, the API returns 202, and you don't find out it's broken until a client asks why nobody's confirming their accounts. Take the extra hour, do it properly, then test with mail-tester.com before you ship. Your future self will not have to explain to a client why their password resets are in spam.
Need help shipping something like this? Get in touch.