← All Posts
GuideKien Phan, Founder

My Emails Aren't Arriving: A Developer's Debugging Guide

The silent failure problem

You send an email through your API. It returns 200 OK. You check your dashboard — it shows 'sent.' But the user says they never got it. This is the most frustrating email problem because there's no error to debug. The email left your server successfully, was accepted by the provider, and then... disappeared somewhere between the provider and the recipient's inbox. It could be in spam, it could have been silently dropped by the ISP, or it could be delayed. Here's how to trace the exact path your email took and find where it got lost.

Step 1: Check the delivery status (not just the send status)

'Sent' doesn't mean 'delivered.' When your email API returns 200, it means the email was accepted for delivery — not that it reached the inbox. There's a pipeline: queued → sending → sent → delivered (or bounced/failed). You need to check the final status, not just the initial acceptance. In AISend, check the email detail page in your dashboard — it shows the full event timeline from queued to delivered, with timestamps for each step. Programmatically, set up webhooks to receive delivery events or poll the email status endpoint.

// Check delivery status after sending
const { id } = await aisend.emails.send({ from, to, subject, html });

// Option 1: Poll status
const email = await aisend.emails.get(id);
console.log(email.status); // "queued" | "sent" | "delivered" | "bounced" | "failed"

// Option 2: Set up webhooks for real-time events
// POST https://yourapp.com/webhooks/email
// { type: "delivered", email_id: "...", timestamp: "..." }

Step 2: Check for bounces and complaints

If the status is 'bounced', the receiving server rejected your email. Hard bounces mean the address doesn't exist — remove it from your list immediately. Soft bounces mean a temporary issue (full mailbox, server down) — retry once, then stop. If the status is 'complained', the recipient marked your email as spam — this is a serious reputation signal. Even a 0.1% complaint rate can trigger ISP filtering. Check your AISend dashboard for bounce and complaint events. Each event includes the reason code from the receiving server, which tells you exactly why delivery failed.

Step 3: Check authentication and spam scoring

If the email shows as 'delivered' but the user can't find it, it's almost certainly in their spam folder. Ask the user to check spam/junk and search for the subject line. If it IS in spam, the issue is usually authentication (SPF/DKIM failing) or content triggers. To diagnose: send a test email to your own Gmail account, open it, click the three dots, and select 'Show original.' Look for 'spf=pass', 'dkim=pass', 'dmarc=pass'. If any show 'fail', fix your DNS records. If authentication passes but emails are still in spam, review your content for spam triggers — excessive links, ALL CAPS, misleading subject lines, or image-heavy layouts with minimal text.

Step 4: Check your sender reputation

ISPs maintain a reputation score for your domain and IP. Low reputation = spam folder. Check your reputation with Google Postmaster Tools (free, covers Gmail) and Microsoft SNDS (covers Outlook/Hotmail). Signs of reputation damage: gradual decline in open rates over weeks, increasing bounce rates, or deliverability that's good for Outlook but bad for Gmail (or vice versa). Common reputation killers: sending to invalid addresses (high bounce rate), sending to users who don't engage (low open rate), sending too much volume too quickly (no warm-up), or having someone on a shared IP send spam. AISend's multi-provider routing helps here — if one provider's reputation dips, your emails automatically route through a healthier provider.

The debugging checklist (use this every time)

When an email isn't arriving, run through this checklist in order. First, check the API response — was the email actually accepted? (If not, fix the API error.) Second, check the delivery status — is it queued, sent, or delivered? (If stuck in queued, check your API key and sending limits.) Third, check for bounces — did the receiving server reject it? (If hard bounce, remove the address.) Fourth, check spam folder — ask the user to search for the subject. (If in spam, check authentication.) Fifth, check authentication — do SPF, DKIM, DMARC pass? (If not, fix DNS records.) Sixth, check content — any spam triggers? (If yes, simplify the email.) Seventh, check reputation — is your domain/IP on any blacklists? (If yes, request delisting.) AISend's dashboard shows steps 1-5 in one view, so you rarely need to dig deeper.

// Set up webhook handler to catch delivery issues automatically
export async function POST(req: Request) {
  const event = await req.json();

  switch (event.type) {
    case "delivered":
      await db.update(emails).set({ deliveredAt: new Date() });
      break;
    case "bounced":
      // Remove invalid address to protect reputation
      await db.update(contacts).set({ invalid: true });
      console.error(`Bounce: ${event.recipient} — ${event.reason}`);
      break;
    case "complained":
      // User marked as spam — stop sending immediately
      await db.update(contacts).set({ unsubscribed: true });
      console.error(`Complaint from ${event.recipient}`);
      break;
  }

  return new Response("OK");
}

Ready to Send Smarter Emails?

3,000 emails/month free. No credit card required.