Debugging Multi-Layer Email Delivery Failures: Gmail SMTP Relay vs. SES API Authentication
Email delivery failures are notoriously difficult to debug because the failure surface spans multiple systems: client-side mail clients, SMTP relay servers, email service providers, DNS infrastructure, and recipient mail servers. This post documents a real incident where emails sent through two different pathways both failed, but for completely different reasons—and how to systematically diagnose and fix each layer.
The Problem Statement
Three emails sent from admin@queenofsandiego.com were not delivering. The sender observed bounces, but the bounces were cryptic: one indicated "misconfigured or out of date" credentials, while others suggested recipient-side rejection. Without systematic investigation, it's easy to blame DNS or assume a global SES configuration problem.
What Actually Happened: Two Independent Failures
Investigation revealed two distinct failure modes operating simultaneously:
- Failure Mode 1 (Client-side): Gmail's "Send mail as" alias for
admin@queenofsandiego.comin thejadasailing@gmail.comaccount had stale SMTP credentials. When attempting to relay through SES SMTP, the authentication failed because the stored SES SMTP password had either been rotated or never properly generated for the current IAM user. - Failure Mode 2 (Infrastructure): Emails that did successfully exit SES via the API were reaching the recipient mail server (Exchange Online at steigerwald-dougherty.com) but were being rejected at the SMTP protocol level, likely due to SPF/DKIM alignment or sender reputation issues.
The critical insight: both failures needed to be fixed independently. Fixing DNS wouldn't help Mode 1 (client credential problem), and refreshing IAM credentials wouldn't help Mode 2 (if emails couldn't get past the recipient's gateway).
Technical Investigation: Layer-by-Layer Diagnosis
Step 1: Verify SES Infrastructure Health
Before troubleshooting SMTP credentials, we validated that the SES region and sender identity were correctly configured:
aws ses list-identities --region us-east-1
aws ses get-identity-dkim-attributes --identities admin@queenofsandiego.com --region us-east-1
This confirmed:
- Domain identity
admin@queenofsandiego.comexists and is verified - All three DKIM CNAME records are properly published in Route53
- SPF record at
queenofsandiego.comincludesinclude:amazonses.com - DMARC policy is set with
_dmarc.queenofsandiego.comTXT record - Custom MAIL FROM domain is configured (mail.queenofsandiego.com)
All DNS infrastructure was correct. The problem wasn't delivery from SES.
Step 2: Check SES Suppression Lists and Account Status
We checked if the recipient address had been suppressed due to bounces or complaints:
aws ses list-suppressed-destinations --region us-east-1 \
--reason BOUNCE --query 'SuppressedDestinationSummaries[*]'
The recipient domain's MX records were valid, and the specific address hadn't been suppressed. This ruled out "emails are being silently dropped due to account suppression."
Step 3: Diagnose the Gmail Alias SMTP Relay Problem
Gmail's "Send mail as" feature allows users to send from alias addresses by relaying through an external SMTP server. The configuration in Gmail typically looks like:
Settings → Accounts and Import → Send mail as
├── SMTP Server: email-smtp.us-east-1.amazonaws.com
├── Port: 587 (TLS)
├── Username: [SES SMTP Username]
└── Password: [SES SMTP Password - derived from IAM secret access key]
The error "misconfigured or out of date" indicates Gmail attempted SMTP authentication and was rejected. The root cause: SES SMTP credentials are derived from AWS IAM secret access keys. If the IAM user's access keys are rotated, the derived SMTP password becomes invalid immediately.
The SMTP password derivation formula for SES (AWS Signature Version 4) is:
SMTP_Password = base64(hmac_sha256("AWS4" + SecretAccessKey, "112358132134"))
# Where the string "112358132134" is fixed (represents us-east-1)
When an IAM key is rotated, even if the old key is still available, the derived SMTP password changes. Gmail was using the old password.
Step 4: Identify the Recipient-Side Rejection (Exchange Online)
For emails that reached the recipient's mail server, the rejection happened at the SMTP protocol level. Exchange Online at steigerwald-dougherty.com validates:
- SPF alignment: Does the sending IP (from SES) match the SPF record of the domain in the From header?
- DKIM signature: Is the DKIM signature for
queenofsandiego.comvalid and present? - DMARC policy: Does the email align with DMARC policy requirements?
- Sender reputation: Is the sending IP/domain known to be malicious?
All of these checked out in our infrastructure validation. The issue was likely that Exchange Online was applying stricter filtering due to:
- Low sender reputation for the specific SES IP assigned to the account
- Email content triggering spam/phishing filters
- The sending domain lacking DMARC
p=quarantineorp=rejectpolicy (it was set top=none)
Key Decisions Made
Decision 1: Separate Client Credential Refresh from Infrastructure Validation
Rather than assume a global SES configuration problem, we isolated the diagnosis. The Gmail alias needed credential refresh in Gmail's web UI—this is outside AWS infrastructure and requires manual intervention in Gmail settings by the account owner.
Decision 2: Strengthened DMARC Policy
The DMARC record was set to p=none (monitoring only). For production email, we recommended updating the _dmarc.queenofsandiego.com TXT record to:
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@queenofsandiego.com; fo=1
This tells recipients: if an email fails DMARC alignment, quarantine it (not reject yet, to avoid breaking legitimate forwarding). The fo=1 parameter generates forensic reports on failures.
Decision 3: Monitor SES Sending IP Reputation
We checked the daemon logs to understand sending patterns. Located at ~/logs/jada_daemon.log on the JADA Lightsail instance, the logs showed all emails were being sent through the same SES SMTP connection