How I Would Fix emails landing in spam in a React Native and Expo AI chatbot product Using Launch Ready.
The symptom is usually simple: users sign up, reset passwords, or get chatbot notifications, but the email arrives in spam or never shows up at all. In an...
How I Would Fix emails landing in spam in a React Native and Expo AI chatbot product Using Launch Ready
The symptom is usually simple: users sign up, reset passwords, or get chatbot notifications, but the email arrives in spam or never shows up at all. In an AI chatbot product built with React Native and Expo, the most likely root cause is not the app itself. It is usually a bad sending setup: missing SPF, DKIM, or DMARC, a weak sending domain reputation, or emails being sent from a shared provider with poor alignment.
The first thing I would inspect is the actual email path: who sends the email, from which domain, through which provider, and whether authentication passes. If the product is shipping from Expo and a backend API, I want to see the exact message headers, DNS records, and sending logs before touching code. Fixing spam issues without that view usually creates more downtime, more support tickets, and more wasted launch time.
Triage in the First Hour
1. Check the sending provider dashboard.
- Look for bounce rate, complaint rate, deferred deliveries, and suppressed recipients.
- If complaint rate is above 0.1 percent or bounce rate is above 2 percent, treat it as a deliverability problem first.
2. Inspect one real message header.
- Confirm SPF = pass.
- Confirm DKIM = pass.
- Confirm DMARC = pass or at least aligned enough to avoid rejection.
3. Review DNS for the sending domain.
- Verify MX, SPF TXT record, DKIM TXT/CNAME records, and DMARC TXT record.
- Check for duplicate SPF records or broken syntax.
4. Open the app flow that triggers email.
- In React Native and Expo, check signup, password reset, magic link login, onboarding invites, and chatbot follow-up flows.
- Confirm which endpoint calls the mail service.
5. Review backend logs for failed sends.
- Look for 4xx/5xx responses from SendGrid, Postmark, SES, Resend, Mailgun, or similar providers.
- Check if retries are happening too aggressively.
6. Inspect environment variables and secrets.
- Confirm API keys are set in production only where needed.
- Make sure no key was pasted into client-side Expo config or committed to git.
7. Check recent deploys.
- Identify any changes to sender name, reply-to address, domain aliasing, redirects, or webhook handlers.
8. Test inbox placement with a seed address set.
- Send to Gmail, Outlook, iCloud Mail, and one corporate mailbox if available.
- Compare inbox vs promotions vs spam placement.
Root Causes
| Likely cause | How to confirm | Why it lands in spam | |---|---|---| | SPF missing or broken | Check DNS TXT record and use provider validation tools | Receiving servers cannot verify your sender identity | | DKIM not enabled | Inspect signed headers for `dkim=pass` | Messages look unauthenticated | | DMARC missing or misaligned | Review DMARC record and alignment between From domain and signing domain | Mail providers distrust unauthenticated brand mail | | Shared sending IP/domain reputation is poor | Check provider reputation metrics and recent complaint spikes | Your mail inherits bad behavior from other senders | | Bad content patterns | Scan subject lines and body for spam-like phrasing or too many links | Filters flag promotional or repetitive content | | App/backend misconfiguration | Review environment variables and server logs for wrong sender address or provider key | Mail may be sent from an unverified domain |
A common mistake in Expo products is assuming the mobile app "sends" email directly. It should not. The app should call a backend endpoint that sends through a verified provider. If email logic lives in client code or relies on exposed secrets anywhere in the app bundle, that is both a deliverability risk and an API security problem.
Here is a quick diagnostic command I would run against DNS:
dig txt yourdomain.com dig txt _dmarc.yourdomain.com dig txt selector1._domainkey.yourdomain.com
If those records do not exist or do not match what the email provider expects, I would stop there and fix authentication before changing templates.
The Fix Plan
1. Lock down the sender architecture.
- Use one sending domain for transactional mail like `mail.yourdomain.com` or `notify.yourdomain.com`.
- Keep marketing mail separate from product alerts if you send both.
- Do not send important user emails from a personal Gmail address or an unverified subdomain.
2. Repair DNS authentication first.
- Add exactly one SPF record for the sending domain.
- Enable DKIM signing in your provider dashboard.
- Add DMARC with at least `p=none` during validation so you can observe failures safely before enforcing stricter policy.
3. Align From address with authenticated domain.
- The visible From address must match the authenticated domain path as closely as possible.
- Avoid display names that look deceptive or change often.
4. Move all sending behind a backend service.
- In React Native and Expo, the app should call your API only.
- The backend should handle retries, rate limits, templates, logging payload IDs only where needed, and secret storage.
5. Clean up secrets handling.
- Store mail provider keys in server-side environment variables only.
- Rotate any key that was exposed in logs, frontend config files like `app.json`, `app.config.js`, or CI output.
6. Simplify templates before resending volume.
- Use plain text plus light HTML structure.
- Remove excessive images, link tracking clutter if not needed yet,
and spammy phrases like "free", "urgent", "act now", unless they are truly required by context.
7. Add throttling on high-volume flows.
- Password resets and invite emails should be rate limited per user and per IP.
- This reduces abuse that can destroy reputation fast.
8. Set up monitoring before redeploying at scale.
- Track delivery success rate above 98 percent.
- Alert on bounce rate above 2 percent and complaint rate above 0.1 percent.
- Watch p95 send latency under 2 seconds if your flow depends on immediate user feedback.
9. Validate Cloudflare and deployment settings if relevant to your stack.
- Make sure redirects do not break verification links.
- Confirm SSL is valid on all subdomains used by APIs and tracking endpoints.
The safest path is boring: authenticate properly first, then reduce risk with backend-only sending and clean templates. I would not chase copy tweaks until DNS alignment passes everywhere.
Regression Tests Before Redeploy
Before shipping again, I would run these checks:
- Send test emails to Gmail, Outlook/Hotmail, iCloud Mail, Yahoo Mail if available.
- Verify inbox placement for signup confirmation, password reset,
chatbot follow-up summary, invite email, payment receipt if applicable, support reply notification if applicable.
Acceptance criteria:
- SPF passes on every test message.
- DKIM passes on every test message.
- DMARC passes or reports aligned results with no unexpected rejects.
- No production secret appears in mobile code bundles or logs.
- No resend loop occurs when a webhook fails once.
- Bounce handling suppresses invalid addresses automatically after 1 failure event where appropriate.
QA checks I would include:
- Test on iPhone and Android builds of the Expo app so you know link flows still open correctly after email changes.
- Click every verification link from mobile mail clients because some clients wrap URLs badly if redirects are broken.
- Confirm empty-state UX when an email has been sent but delivery may take up to 60 seconds instead of showing an error too early.
I also want one security gate here: confirm that API endpoints used by the app require auth where needed and reject arbitrary recipient addresses unless they are part of an approved user action like signup or password reset request. That prevents abuse that can sink deliverability again within days.
Prevention
The issue comes back when teams treat email as a one-time setup task instead of part of production operations. I would put these guardrails in place:
- Monitoring:
- Delivery success dashboard
- Bounce alerts
- Complaint alerts
- Provider status page monitoring
- Uptime checks on webhook endpoints
- Code review:
- No direct mail credentials in React Native code
- No hidden fallback sender addresses
- No unbounded retry loops
- No duplicate send paths across mobile app and backend
- Security:
- Least privilege API keys
- Rotated secrets every time there is suspicion of exposure
- Rate limiting on auth-related endpoints
- Logging without sensitive message bodies unless absolutely necessary
- UX:
- Show "Check your inbox" states clearly after signup
- Offer resend after a short delay like 30 to 60 seconds
- Explain spam folder checks without sounding broken
- Provide support escalation if delivery fails twice
- Performance:
- Queue non-blocking emails so user actions do not wait on slow SMTP calls
- Keep p95 send time under 2 seconds for transactional requests
```mermaid flowchart TD A[App event] --> B[API] B --> C[Queue] C --> D[Mail svc] D --> E[DNS check] D --> F[Inbox test] F --> G[Alert]
If you already have analytics around onboarding drop-off, I would compare "email sent" against "email opened" weekly so you catch deliverability drift before it becomes churn. ## When to Use Launch Ready Use Launch Ready when you need this fixed fast without turning it into a long engineering project. It fits founders who have a working React Native plus Expo AI chatbot product but need domain setup, email deliverability, Cloudflare, SSL, deployment, secrets, and monitoring cleaned up in one controlled sprint. It includes DNS, redirects, subdomains, Cloudflare, SSL, caching, DDoS protection, SPF/DKIM/DMARC, production deployment, environment variables, secrets, uptime monitoring, and a handover checklist. What I need from you before starting: - Domain registrar access - Cloudflare access if already connected - Email provider access like SES, SendGrid, Postmark, Resend, or Mailgun - Backend repo access - Expo project access - Current production URLs - A list of critical email flows: signup, reset password, invites, chatbot summaries If your team has already shipped something broken into production once, I would not guess my way through another deploy window. I would audit it properly first so we fix root cause instead of just moving spam around between providers. ## References - https://roadmap.sh/api-security-best-practices - https://roadmap.sh/cyber-security - https://roadmap.sh/qa - https://www.rfc-editor.org/rfc/rfc7208.html - https://www.rfc-editor.org/rfc/rfc6376.html --- ## Take the next step If this is a problem in your product right now, here is what to do next: - **[Use the free Cyprian tools](/tools)** - estimate cost, score app risk, check launch readiness, or pick the right service sprint. - **[Book a discovery call](/contact)** - I will tell you honestly whether you need a sprint or if you can DIY the next step. *Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*
Cyprian Tinashe Aarons — Senior Full Stack & AI Engineer
Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.