Your App's Emails Aren't Sending (Or They're Going to Spam)
Your app needs to send emails — password resets, confirmations, notifications. You set it up. It worked in testing. Now users say they never got the email, or they found it in spam, or some email providers work and others don't.
Email delivery is one of the most deceptively complex parts of running an app. The internet has spent decades building systems to prevent spam, and your app's emails have to prove they're legitimate to every one of those systems.
Problem 1: Emails aren't sending at all
If no emails are going out, it's usually one of these:
SMTP credentials are wrong. Check your email sending configuration. You need a host, port, username, and password. Common mistake: using your personal email password instead of an app-specific password or API key.
# Common SMTP settings
# Gmail (requires app-specific password):
Host: smtp.gmail.com
Port: 587
Security: STARTTLS
# SendGrid:
Host: smtp.sendgrid.net
Port: 587
Username: apikey
Password: your-sendgrid-api-key
# Mailgun:
Host: smtp.mailgun.org
Port: 587
Port is blocked. Many hosting providers (AWS, GCP, some VPS providers) block port 25 by default to prevent spam. Use port 587 (STARTTLS) or 465 (SSL) instead. If those are also blocked, you'll need to use an email API instead of SMTP.
Environment variables aren't set. Your SMTP credentials work locally because they're in your .env file. They're not in your production environment. Check your hosting platform's environment variable settings.
Gmail's sending limits. If you're sending through a personal Gmail account, Google limits you to about 500 emails per day and will lock your account if you look like you're sending automated mail. Don't use personal Gmail for production apps.
Problem 2: Emails go to spam
If emails send but land in spam, the receiving email servers don't trust your emails. There are three DNS records that establish trust: SPF, DKIM, and DMARC.
SPF (Sender Policy Framework). A DNS record that says "these servers are allowed to send email from my domain." Without it, any server can send email pretending to be you, so email providers treat unsigned emails as suspicious.
# Example SPF record (TXT record on your domain):
v=spf1 include:sendgrid.net include:_spf.google.com ~all
This says: "SendGrid and Google are authorized to send email from my domain. Treat everyone else as suspicious."
DKIM (DomainKeys Identified Mail). A cryptographic signature that proves the email was actually sent by someone authorized to use your domain. Your email provider gives you a DKIM record to add to your DNS.
# Example DKIM record (CNAME or TXT record):
# Name: s1._domainkey.yourdomain.com
# Value: (provided by your email service)
DMARC (Domain-based Message Authentication). Tells receiving servers what to do with emails that fail SPF and DKIM checks. Without DMARC, providers make their own decision (usually spam folder).
# Minimal DMARC record (TXT record):
# Name: _dmarc.yourdomain.com
v=DMARC1; p=none; rua=mailto:[email protected]
Start with p=none (monitor only). Once you're confident your SPF and DKIM are correct, change to p=quarantine or p=reject.
Problem 3: Some providers work, others don't
If Gmail works but Outlook doesn't, or vice versa, each provider has different spam thresholds. But the usual suspects are:
- Missing or incorrect DNS records. Some providers are stricter about SPF/DKIM/DMARC than others.
- Your sending IP is blacklisted. If you're on shared hosting or a cheap VPS, your IP may have been used for spam by someone else. Check at
mxtoolbox.com/blacklists.aspx. - Email content looks spammy. Short emails with just a link, all-caps subjects, or HTML with no text version — these trigger spam filters.
- No reverse DNS (PTR record). Your server's IP should resolve back to your domain. Most VPS providers let you set this in their control panel.
The right approach for production apps
Don't send email directly from your app server. Use a transactional email service:
- SendGrid — free tier: 100 emails/day
- Mailgun — free tier: 100 emails/day for 3 months
- Postmark — focused on transactional email, excellent deliverability
- Amazon SES — cheapest at scale, more setup required
- Resend — developer-focused, modern API
These services handle SPF/DKIM/DMARC configuration, maintain sender reputation, manage bounces and complaints, and provide delivery tracking. They solve the hard parts of email delivery so you don't have to.
How to check your setup
# Check SPF record
dig TXT yourdomain.com | grep spf
# Check DKIM record
dig TXT s1._domainkey.yourdomain.com
# Check DMARC record
dig TXT _dmarc.yourdomain.com
# Send a test email and check headers
# In Gmail: Open email → Three dots → "Show original"
# Look for SPF: PASS, DKIM: PASS, DMARC: PASS
If any of those show FAIL, that's your problem. The header tells you exactly which check failed and why.
Why AI gets this wrong
AI can generate the code to send emails. It can't set up your DNS records, configure your email service, or debug deliverability issues. Email is an infrastructure problem, not a code problem. Your sendEmail() function might be perfect, but if your domain isn't authenticated, the emails will still go to spam.
AI also tends to use the simplest possible setup — direct SMTP from the app server — which is the approach most likely to have deliverability problems. A developer knows to use a transactional email service from the start, because they've been through the pain of debugging email delivery before.
Emails still not arriving?
MeatButton connects you with developers who can diagnose your email delivery setup, configure your DNS records, and make sure your users actually get your emails. First one's free.
Get MeatButton