Debugging Email Delivery Failures: Diagnosing Gmail SMTP Relay vs. SES Infrastructure Issues
During a recent development session, we encountered email delivery failures across multiple channels. What appeared to be a single problem turned out to be two distinct failure modes: a Gmail "Send mail as" SMTP relay authentication issue and a separate downstream rejection by an external mail server. This post walks through the diagnostic approach and the specific technical checks that revealed the root causes.
The Problem Statement
Three emails in a thread were bouncing. The error message indicated a misconfigured or out-of-date SMTP relay, but the actual infrastructure—domain verification, DNS records, and SES configuration—appeared healthy. We needed to determine whether the problem was in our sending infrastructure, Gmail's relay configuration, or the recipient's mail server.
Diagnostic Approach: Layered Infrastructure Inspection
Rather than guessing, we systematically validated each layer of the email delivery stack:
- SES Account Status & Configuration: Verified verified identities, suppression lists, and configuration sets in both us-east-1 and us-west-2 regions
- Domain Authentication Records: Checked SPF, DKIM (all 3 CNAME records), DMARC, and custom MAIL FROM configuration
- SMTP Credentials: Derived SES SMTP credentials from current IAM user and tested authentication against the SES SMTP endpoint
- Gmail Configuration: Inspected the "Send mail as" alias setup for
admin@queenofsandiego.comin thejadasailing@gmail.comaccount - Recipient Mail Server: Checked MX records and SMTP policies for the recipient domain
Technical Details: What We Found
Layer 1: SES Infrastructure (Clean)
The SES configuration was fully functional:
# SES Identity verification
aws ses list-identities --region us-east-1
aws ses get-identity-dkim-attributes --identities admin@queenofsandiego.com --region us-east-1
# Results: All 3 DKIM CNAME records present in DNS
# SPF record: v=spf1 include:amazonses.com ~all
# DMARC record: v=DMARC1; p=none; rua=mailto:...
# Custom MAIL FROM: bounce.queenofsandiego.com with correct CNAME
Suppression lists were inspected to ensure no addresses were being artificially rejected:
aws ses list-suppressed-destinations --reason BOUNCE --region us-east-1
aws ses list-suppressed-destinations --reason COMPLAINT --region us-east-1
This confirmed that SES itself was not the bottleneck.
Layer 2: SMTP Credentials (Authentication Verified)
We derived SES SMTP credentials from the current IAM user using the documented AWS SES v4 signature algorithm. This is critical because SES SMTP credentials are not traditional username/password pairs—they're derived from IAM access keys using a specific hashing algorithm:
# AWS SES SMTP v4 credential derivation (pseudocode)
# Input: IAM AccessKeyId, IAM SecretAccessKey
# SMTP Username: AccessKeyId
# SMTP Password: derived via HMAC-SHA256 signing with specific message format
# Result was tested against:
aws-ses-smtp-endpoint: email-smtp.us-east-1.amazonaws.com:587
SMTP authentication succeeded, proving that the SES endpoint itself was accepting our credentials and ready to relay mail.
Layer 3: Gmail "Send mail as" Configuration (Stale Credentials)
Screenshots of the bounce revealed the real issue: the email originated from jadasailing@gmail.com using the "Send mail as" feature to relay through admin@queenofsandiego.com. Gmail's error indicated that the SMTP relay credentials stored in Gmail's settings for that alias were either expired or no longer valid.
This is a common failure mode when:
- SES SMTP credentials are rotated (either manually or by IAM policy)
- The alias was configured with credentials that have since been invalidated
- The original person who set up the alias used temporary credentials that expired
- An IAM user's permissions were restricted or the access key was regenerated
Because Gmail itself attempted the SMTP connection and failed before ever handing off to SES, the bounce came back to the Gmail account (jadasailing@gmail.com), not to the spoofed sender address.
Layer 4: Recipient Mail Server (Secondary Rejection)
A separate email in the thread that did successfully send via SES API was rejected by the recipient's mail server (Exchange Online at steigerwald-dougherty.com). This was a policy rejection, not an infrastructure failure—the recipient's organization may have had content filters, sender reputation checks, or SPF/DKIM validation that failed on their side.
Key Technical Decisions
Why we checked SES first: SES is where most of our outbound email originates. If SES suppression lists were blocking addresses or if domain verification had issues, that would explain widespread failures. By eliminating infrastructure problems early, we narrowed the scope.
Why we derived SMTP credentials: Rather than searching for credentials in config files (which might be stale), we derived them fresh from the current IAM user. This gave us the current, valid credential state and let us test authentication in real-time.
Why we checked DNS and DKIM in detail: Email authentication is fragile. A single missing DKIM CNAME or an incorrect SPF record can cause rejections that look like infrastructure failures but are actually configuration errors. By validating all 3 DKIM records, SPF, DMARC, and custom MAIL FROM, we eliminated DNS as a variable.
Why we distinguished between Gmail relay failure and SES failure: The error message mentioned SMTP relay configuration, which pointed to Gmail—not SES. By examining the bounce carefully, we saw that Gmail itself was rejecting the send before it ever reached SES. This distinction changes the remediation entirely.
The Fix
The immediate solution involves updating Gmail's "Send mail as" configuration for the admin@queenofsandiego.com alias:
- Navigate to Gmail Settings → Accounts and Import → "Send mail as"
- Edit the alias entry for
admin@queenofsandiego.com - Update SMTP Server to
email-smtp.us-east-1.amazonaws.com, port 587 - Use the current SES SMTP credentials derived from the active IAM user
- Complete the verification flow that Gmail requires
For the secondary rejection at the recipient's mail server, we'd need to work with their mail administrator or ensure sender reputation and content filtering are not blocking our domain.
What's Next
To prevent this from recurring:
- Document the SES SMTP credential derivation process and version it with our infrastructure-as-code
- Set up monitoring on SES configuration changes and IAM credential rotations
- Create a checklist for validating email alias configurations across all sending channels