@Mail Domain Check

Amazon Cognito · user state · Amazon SES

AWS Cognito verification email not received: trace the code-delivery path

A successful Cognito API response or CodeDeliveryDetails identifies an intended delivery channel; it is not an inbox receipt. Follow one request through user state, recovery settings, the Cognito mail mode, Amazon SES, and receiver evidence before retrying.

Start with the boundary map

1. Cognito request
Record the operation, user pool, app path, region, UTC time, random correlation ID, bounded response, and any CodeDeliveryDetails. Signup, confirmation resend, invitation, and password recovery have different preconditions.
2. User and recovery state
Check the user's status, verified recovery attributes, account-recovery configuration, and intended delivery medium. A request can succeed without selecting the mailbox the operator expected.
3. Cognito email mode
Identify COGNITO_DEFAULT versus DEVELOPER with Amazon SES. Default quotas and custom-identity requirements belong to this boundary.
4. Amazon SES
For the SES path, prove identity, region, permissions, sandbox or production state, quota, suppression state, and a matching event trail.
5. SMTP and receiver
A provider Delivery event means the receiving server accepted the message. It does not prove inbox placement, visibility, or mailbox control.
6. Code use
If the message arrived but the code is invalid or expired, investigate code timing, retries, and account state separately from transport.

Build the first-action plan locally from observed states only. No email address, message, code, token, or credential is entered.

Never paste an AWS access key, secret access key, session token, Cognito app client secret, SECRET_HASH, JWT, verification code, recipient address, message, SES SMTP password, provider API key, webhook secret, seed phrase, private key, or wallet signature into a public diagnostic or incident post.

Prove which Cognito operation ran

Start from the exact API or managed-UI operation. SignUp, ResendConfirmationCode, ForgotPassword, and AdminCreateUser do not share identical eligibility, user-state, or message-template behavior. Preserve the bounded HTTP status, AWS request ID, user-pool region, timestamp, and delivery medium without logging a recipient or secret.

  • SignUp can create an UNCONFIRMED user and return delivery details, but that response does not prove an SES event or receiver acceptance.
  • ResendConfirmationCode applies to an eligible unconfirmed user. A confirmed account needs a different diagnosis.
  • ForgotPassword requires an eligible verified recovery attribute selected by the user pool's account-recovery settings.
  • AdminCreateUser normally creates a FORCE_CHANGE_PASSWORD invitation flow; suppressed invitations, temporary-password behavior, and message-template settings belong to that path.

For privacy and account-discovery resistance, Cognito can avoid revealing whether a username exists. A generic success response is therefore not evidence that a message was created for a particular person.

Check user state and the selected destination

Read the user privately in the correct user pool and region. Compare UserStatus, the presence of the email attribute, email_verified, enabled aliases, and AccountRecoverySetting. Do not copy the attribute value into an external ticket.

  1. Confirm that the application is calling the intended user pool and app client in the intended AWS region.
  2. Classify UNCONFIRMED, CONFIRMED, and FORCE_CHANGE_PASSWORD before choosing signup confirmation, password recovery, or invitation actions.
  3. For ForgotPassword, prove that a verified attribute is eligible under the current recovery priority. An unverified email can exist without being a usable password-recovery destination.
  4. Compare the masked destination and DeliveryMedium in CodeDeliveryDetails with the expected channel without exposing the underlying address.

Identify the Cognito email mode

Read the user pool's EmailSendingAccount. With COGNITO_DEFAULT, Cognito sends through an AWS-managed path with a deliberately small daily quota. AWS documented 50 messages per day at this guide's publication; consult current quotas instead of treating that number as permanent.

With DEVELOPER, the user pool sends through the account's Amazon SES configuration. Verify the exact SourceArn, From identity, configuration set, and supported SES region. A verified identity in a different region does not prove that the configured user-pool path can use it.

  • Check CloudTrail and bounded Cognito errors for authorization, identity, quota, template, Lambda trigger, or configuration failures.
  • If a custom email-sender Lambda trigger is configured, treat its invocation and encryption/decryption path as a separate application boundary.
  • Do not add broad IAM permissions as a diagnostic shortcut. Correct the specific identity, region, sending-authorization, or role relationship named by the evidence.

Trace the Amazon SES boundary

In the SES sandbox, sending is restricted to verified recipients or the mailbox simulator, even when the From identity is verified. Request production access in the relevant region before using the path for real users. Also inspect the current sending quota and rate rather than assuming another region's status applies.

  1. Verify the exact email address or domain identity used by the Cognito configuration in the same supported SES region.
  2. Check the account-level and global suppression lists before one controlled retry. Remove a suppression only after the underlying bounce or complaint condition is understood.
  3. Use a configuration set and event destination to capture Send, Delivery, Bounce, Complaint, Reject, Rendering Failure, and DeliveryDelay evidence.
  4. Correlate by AWS request ID, SES message ID, event time, template, and bounded destination domain. Do not publish the recipient or message.

A Send event means SES accepted the request for sending. A Delivery event means the recipient's mail server accepted the message. Neither event proves that the user saw it in the inbox.

After receiver acceptance, inspect private filtering

Search the mailbox's own interface, spam or junk, quarantine, security gateways, category tabs, aliases, forwarding, groups, rules, and storage. If only one receiving domain is affected, involve its mail administrator with the SES message ID, acceptance time, visible From domain, and bounded SMTP evidence.

When a controlled message can be found, export its complete original header. Compare trusted receiver timestamps with the SES event, then read the final receiver's Authentication-Results, visible From, DKIM d=, SPF identity, DMARC alignment, and newest trusted Received fields. Analyze the header locally without uploading it.

For a bounce or delay, preserve the complete SMTP response and decode it locally. Separate temporary 4xx deferrals from permanent 5xx failures before changing DNS or retry behavior.

The first ten minutes

  1. Record operation, UTC time, user-pool region, app path, scope, AWS request ID, and bounded response.
  2. Classify user status, verified recovery attribute, recovery priority, delivery medium, and masked destination.
  3. Identify COGNITO_DEFAULT, DEVELOPER, or a custom sender trigger and stop at the first missing proof.
  4. For SES, check region, identity, sandbox state, quota, suppression, configuration-set events, and the exact message ID.
  5. After receiver acceptance, check private filtering and obtain a trusted original header when possible.
  6. Name one owner, one corrective action, and the evidence required before one controlled retry.

Build a safe incident packet

Application
Operation, app path, UTC time, random correlation ID, scope, template version, and bounded client or server error.
Cognito
User-pool region, request ID, user status, delivery medium, masked destination, recovery setting, and email mode.
Amazon SES
Region, identity ARN without credentials, sandbox or production state, quota state, SES message ID, ordered event names, and bounded failure reason.
Receiver
Affected domain and scope, SMTP diagnostic, quarantine or rule evidence, and a controlled original header when available.
Exclusions
No recipient, message, verification code, token, password, access key, secret, session credential, SMTP credential, API key, or wallet secret.
Next action
The first unproven boundary, its owner, one corrective action, and the condition for one controlled retry.

Inventory the Cognito sending path locally so user pool, region, email mode, From domain, SES identity, DKIM identity, Return-Path, event destination, and incident owner remain visible.

Check the visible From domain's public sender controls. Public DNS can confirm published SPF, DKIM, DMARC, PTR, and transport-policy evidence, but it cannot read Cognito, SES, or a mailbox.

This independent guide is not affiliated with Amazon Web Services. Cognito, CloudTrail, and Amazon SES are the sources of truth for their private boundaries; the receiving administrator remains the source of truth for private filtering.

Primary references