Debugging Multi-Layer Email Delivery Failures: Gmail Relay Credentials vs. Exchange Online Rejection
When emails aren't delivering, the failure often isn't in your primary email infrastructure—it's in the relay chain. This post covers a real debugging session where we found two distinct failure points in a single email thread: stale SMTP credentials in Gmail's "Send mail as" alias, and a separate rejection at the recipient's Exchange Online server.
The Problem: Two Different Bounces, One Thread
The initial symptom appeared as a single error message, but it masked two separate failures:
- Failure 1 (Client-side): Gmail's "Send mail as" alias had misconfigured SES SMTP relay credentials
- Failure 2 (Server-side): A separate email that successfully left SES was rejected by the recipient's Exchange Online server
Without systematic diagnosis, these would have been conflated into a single "email not sending" problem. The session involved checking SES infrastructure, Gmail alias configuration, DNS records, and recipient-side filtering—each requiring different tools and validation approaches.
Diagnosing the Gmail Relay Failure
The first bounce came back to jadasailing@gmail.com with a "misconfigured or out of date" SMTP error. This indicated the problem was in Gmail's email relay, not in the destination.
Why this happens: When you add a "Send mail as" alias in Gmail, you configure an external SMTP server. Gmail stores those credentials and uses them to relay outbound mail through that server. If the credentials rotate or expire, Gmail silently fails on send and bounces the message back to the real account.
Root cause: The alias was configured to relay through AWS SES SMTP (endpoint: email-smtp.us-east-1.amazonaws.com), but the stored credentials were stale. SES SMTP credentials are derived from IAM keys using AWS's v4 signature algorithm—if the underlying IAM key is rotated, all dependent SMTP credentials become invalid.
Verification approach: We retrieved the current IAM credentials and derived the correct SES SMTP password using the documented AWS v4 derivation algorithm:
aws iam get-access-key-last-used --access-key-id [KEY_ID]
# Then derive SMTP password from current credentials using AWS SigV4 algorithm
# Test connectivity to SES SMTP endpoint on port 587
The test confirmed that the current IAM credentials could authenticate to SES SMTP, but the credentials stored in Gmail's alias configuration could not. This meant the fix was: update the alias in Gmail's settings to use the current SES SMTP credentials.
Diagnosing the Exchange Online Rejection
A separate email in the thread had actually reached SES successfully and been sent onward, but was rejected by the recipient's Exchange Online server. This required a different diagnostic path entirely.
SES infrastructure validation: We confirmed the sending domain's email authentication was complete:
- SPF record: Configured at DNS for
queenofsandiego.comto authorize SES SMTP endpoints - DKIM: All three CNAME records present in DNS, pointing to SES's token verification endpoints
- DMARC: Policy record configured; rejection mode set appropriately
- Custom MAIL FROM domain: Configured in SES to use a subdomain (e.g.,
mail.queenofsandiego.com) for additional deliverability
DNS validation commands:
# Check SPF
dig queenofsandiego.com TXT | grep v=spf1
# Check DKIM CNAME records (SES creates three tokens)
dig [token-1]._domainkey.queenofsandiego.com CNAME
dig [token-2]._domainkey.queenofsandiego.com CNAME
dig [token-3]._domainkey.queenofsandiego.com CNAME
# Check DMARC
dig _dmarc.queenofsandiego.com TXT
# Check custom MAIL FROM domain MX
dig mail.queenofsandiego.com MX
All records were properly configured, meaning the email left SES with valid authentication headers. The rejection therefore came from the recipient domain's email filtering policies—likely a combination of content filtering, sender reputation scoring, or explicit blocklisting.
Infrastructure Architecture: The Relay Chain
Understanding the full path helps explain why two separate failures occurred:
Sender (jadasailing@gmail.com)
└─ Gmail "Send mail as" alias (admin@queenofsandiego.com)
└─ SMTP relay to SES (email-smtp.us-east-1.amazonaws.com:587)
└─ SES validates SPF/DKIM/DMARC
└─ Sends to recipient MX servers
└─ Recipient Exchange Online checks content & reputation
└─ Delivers or rejects
Failure 1 occurred at step 2 (Gmail couldn't authenticate to SES). Failure 2 occurred at step 4 (recipient server rejected despite valid authentication).
Key Decisions and Patterns
Why check Gmail alias configuration first? The bounce message itself indicated the failure point: it came back to jadasailing@gmail.com, not to the reply-to or return-path address. This is Gmail's behavior when it fails at the SMTP relay stage before the message ever leaves Gmail's infrastructure.
Why verify all SES infrastructure before blaming the recipient? Email authentication failure (missing DKIM, bad SPF) causes immediate rejection. If the authentication checks passed on the recipient side (as indicated by the message reaching an Exchange rule rather than being rejected at the MX layer), it meant our infrastructure was sound. The rejection was therefore based on the message content or sender reputation, which are outside our direct control but diagnostically different from an authentication failure.
Why use AWS's v4 signature algorithm for SMTP password derivation? SES SMTP credentials aren't randomly generated like typical SMTP passwords. They're deterministically derived from IAM credentials using AWS's Signature Version 4 algorithm. This makes them auto-invalidate when the underlying IAM key changes, but requires proper re-derivation when updating. Attempting to manually set an SMTP password in Gmail without using the correct algorithm would fail immediately.
What's Next
- Update Gmail alias credentials: Access
Gmail Settings → Accounts and Import → Send mail as, edit the alias, and update the SMTP password field with the newly derived SES credential. - Test relay: Send a test message through the alias to confirm Gmail can now reach SES SMTP.
- Investigate recipient-side filtering: Check with the recipient domain owner about content policies, IP reputation, or explicit allowlist requirements. Provide the email headers from the rejected message for analysis.
- Monitor SES bounce and complaint rates: Track
jada-blast-schedulerLambda function logs and SES suppression list growth to catch future credential rotation issues proactively.
The core lesson: when debugging email delivery, map the full relay chain and test each hop independently. A single failed message can mask multiple infrastructure issues; systematic diagnosis prevents fixing the wrong thing.