Skip to main content

AWS SES Email Validation: API Lookup vs Auto Validation

11 min read By Tom C

AWS SES added native email validation in December 2025, and it solves a real problem. Invalid email addresses damage your sender reputation, inflate bounce rates, and — once you cross the thresholds that mailbox providers care about — get your sending domain throttled or blocked. For high-volume senders, bad list hygiene is an expensive problem.

There are two validation approaches in SES, and the difference in how they work — and what they cost — is significant enough that choosing the wrong one for your use case could cost considerably more than it should.

What validation actually checks

Both methods run the same underlying checks against each address. The GetEmailAddressInsights API returns granular results across 6 evaluations:

Evaluation What it checks
HasValidSyntax RFC-compliant format and character validation
HasValidDnsRecords Whether the domain exists and is configured to receive email
MailboxExists Whether the mailbox exists — without sending anything
IsRoleAddress Role-based addresses: admin@, support@, info@, etc.
IsDisposable Temporary or throwaway email providers
IsRandomInput Randomly generated patterns (junk signups, bots)

Each evaluation returns a confidence verdict of HIGH, MEDIUM, or LOW. The overall IsValid verdict rolls these up:

  • HIGH — strong delivery likelihood
  • MEDIUM — moderate delivery likelihood
  • LOW — unlikely to deliver

Auto validation uses the same checks but acts on them silently, suppressing outbound sends that fall below your chosen threshold before they leave your account.

The API lookup: powerful, but expensive

The GetEmailAddressInsights API validates a single address on demand and returns the full breakdown. The AWS CLI call looks like this:

aws sesv2 get-email-address-insights \
  --email-address user@example.com \
  --region eu-west-1

The response gives you everything you need to make a routing decision:

{
  "MailboxValidation": {
    "IsValid": {
      "ConfidenceVerdict": "HIGH"
    },
    "Evaluations": {
      "HasValidSyntax":   { "ConfidenceVerdict": "HIGH"   },
      "HasValidDnsRecords": { "ConfidenceVerdict": "HIGH" },
      "MailboxExists":    { "ConfidenceVerdict": "MEDIUM" },
      "IsRoleAddress":    { "ConfidenceVerdict": "LOW"    },
      "IsDisposable":     { "ConfidenceVerdict": "LOW"    },
      "IsRandomInput":    { "ConfidenceVerdict": "LOW"    }
    }
  }
}

In a Rails application, you'd call this via the AWS SDK at the point of collection:

require "aws-sdk-sesv2"

class EmailValidator
  def self.validate(email_address)
    client = Aws::SESV2::Client.new(region: "eu-west-1")

    response = client.get_email_address_insights(
      email_address: email_address
    )

    validation = response.mailbox_validation
    verdict = validation.is_valid.confidence_verdict
    evaluations = validation.evaluations

    {
      valid: verdict == "HIGH",
      verdict: verdict,
      disposable: evaluations.is_disposable.confidence_verdict == "HIGH",
      role_address: evaluations.is_role_address.confidence_verdict == "HIGH",
      random_input: evaluations.is_random_input.confidence_verdict == "HIGH"
    }
  rescue Aws::SESV2::Errors::ServiceError => e
    Rails.logger.error("SES validation error for #{email_address}: #{e.message}")
    { valid: true, verdict: "UNKNOWN" } # Fail open if the API is unavailable
  end
end

Using it in a sign-up flow:

class RegistrationsController < ApplicationController
  def create
    result = EmailValidator.validate(params[:email])

    if result[:disposable]
      return render :new,
        alert: "Disposable email addresses are not accepted."
    end

    if result[:verdict] == "LOW"
      return render :new,
        alert: "That email address doesn't appear to be valid."
    end

    # Optionally warn on MEDIUM without blocking:
    if result[:verdict] == "MEDIUM"
      flash.now[:notice] = "Please double-check your email address."
    end

    @user = User.new(user_params)
    # ... rest of registration
  end
end

The cost: $0.01 per validation. That's $10 per 1,000 addresses — or $10,000 per million. For a SaaS application with a healthy sign-up rate, this adds up. At 10,000 new accounts per month, you're looking at $100/month just in validation API calls.

Auto validation: cheap, silent, and automatic

Auto validation intercepts outbound sends and suppresses any that don't meet your threshold. It requires no code changes — you configure it once in the SES console or via the API, and it runs automatically on everything you send.

3 threshold options:

  • SES Managed — AWS dynamically adjusts the threshold based on your sending patterns. The recommended default for most senders.
  • High — Only sends to addresses with a HIGH confidence verdict. Maximum protection, but may suppress some legitimate addresses that couldn't be fully verified (common with some enterprise mail servers that block mailbox probing).
  • Medium — Sends to HIGH and MEDIUM verdict addresses. Better reach with still-meaningful protection.

You can set this at account level and override per configuration set, which is useful if you have a transactional sending stream where deliverability is critical and a marketing stream where you want slightly looser thresholds:

# Enable at account level with SES-managed threshold
aws sesv2 put-account-suppression-attributes \
  --region eu-west-1 \
  --cli-input-json '{
    "SuppressedReasons": ["BOUNCE", "COMPLAINT"],
    "ValidationOptions": {
      "ConditionThreshold": {
        "ConditionThresholdEnabled": "ENABLED"
      }
    }
  }'

# Override for a specific configuration set — High threshold
aws sesv2 put-configuration-set-suppression-options \
  --configuration-set-name transactional \
  --region eu-west-1 \
  --cli-input-json '{
    "SuppressedReasons": ["BOUNCE", "COMPLAINT"],
    "ValidationOptions": {
      "ConditionThreshold": {
        "ConditionThresholdEnabled": "ENABLED",
        "OverallConfidenceThreshold": {
          "Verdict": "HIGH"
        }
      }
    }
  }'

The cost: $0.01 per 1,000 validations. That's $0.00001 per email — roughly 1,000 times cheaper than the API lookup. Sending a million emails per month in auto-validation mode costs you $10.

The critical catch with auto validation

Before you set auto validation to HIGH and assume your list is being cleaned: suppressed sends still incur charges.

If auto validation prevents SES from sending to an address, you still pay:

  • The standard outgoing message fee ($0.10 per 1,000 emails)
  • The auto validation fee ($0.01 per 1,000 validations)

You are paying to not send email. This is the main reason auto validation is not a substitute for list hygiene — it reduces your bounce rate and protects your reputation, but it doesn't reduce your send costs. For large lists with significant invalid address percentages, you'd be better served cleaning the list before sending rather than relying on suppression.

When to use which

Use the API lookup when:

  • Validating at point of collection — sign-up forms, import flows, subscription opt-ins. The cost per validation is justified by the long-term benefit of not adding a bad address to your list in the first place. A bad address added at sign-up might be emailed hundreds of times over its lifetime; $0.01 to reject it is cheap.
  • You want user-facing feedback. Auto validation is silent — it suppresses sends without telling your application why. The API gives you the granular breakdown to show the user a useful message, or to implement different policies for disposable vs invalid addresses.
  • You need to detect disposable or role-based addresses as a business policy decision, independent of deliverability. A genuine mailbox that happens to be at a disposable domain will have MailboxExists: HIGH — auto validation won't suppress it, but the API will flag it.

Use auto validation when:

  • You want a low-cost safety net on all outbound sends. Enable SES-managed auto validation at account level and forget about it. For $10 per million sends, it's background insurance.
  • You have legacy data being mailed for the first time and don't want to run it through the API. The auto validation will suppress the worst addresses without the $0.01-per-address cost of a full API scan.
  • You're running a campaign list acquired through channels where you can't validate addresses at collection time.

Don't use the API to clean an existing list at scale. If you have 500,000 email addresses and want to validate them all before a campaign, that's $5,000 in API calls. Run the campaign through auto validation instead, process the bounce and suppression events, and remove the bad addresses from your list based on the results.

A practical setup for most applications

For most Rails applications sending transactional email, this combination works well:

  1. API validation at sign-up. Call GetEmailAddressInsights when a user registers or provides an email address. Block LOW verdicts and disposable addresses. Warn on MEDIUM without blocking (some legitimate corporate email servers return MEDIUM because they don't respond to mailbox probes). Log the full evaluation breakdown for later analysis.

  2. Auto validation at SES-managed threshold, account-wide. Turn it on and leave it. It costs almost nothing and provides a backstop against addresses that slipped through or that have become invalid since collection.

  3. Monitor your bounce and complaint rates. SES will warn you when you approach the thresholds that affect sender reputation. Combined with the validation setup above, you should rarely see those warnings.

The IAM policy you need for the API validation:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SESEmailValidation",
      "Effect": "Allow",
      "Action": [
        "ses:GetEmailAddressInsights",
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": "*"
    }
  ]
}

The role address question

IsRoleAddress catches addresses like admin@, info@, support@, noreply@, and postmaster@. Whether to block these depends on what you're sending.

For transactional email (password resets, receipts, account notifications), blocking role addresses is reasonable. These addresses typically go to shared inboxes or ticketing systems rather than the individual the email is intended for, and they have higher complaint rates.

For B2B SaaS where the customer signs up with their company's support@ or info@ address, blocking role addresses would reject legitimate customers. In this case, log the flag and treat it as a data quality signal rather than a hard block.

The granularity of the API is exactly why it's worth the cost at collection time: you can apply nuanced business logic that auto validation can't.


If you're working on email deliverability, SES configuration, or AWS infrastructure more broadly, we're happy to help.