Profiles·Public

@aws-sdk/client-ses

semver^3.0.0postconditions58functions27last verified2026-06-24coverage score82%

Postconditions: what we check

  • send · ses-send-no-try-catch
    error
    WhensesClient.send() called with any SES command without try-catch wrapping the await expression
    ThrowsMessageRejected (400) — content flagged as spam/virus/policy violation; MailFromDomainNotVerifiedException (400) — custom MAIL FROM domain has invalid MX record; AccountSendingPausedException (403) — SES sending paused at account level; ConfigurationSetSendingPaused (400) — sending disabled on the named config set; ConfigurationSetDoesNotExist (400) — named configuration set not found; LimitExceededException (400) — sending quota or rate limit exceeded; InvalidParameterValue (400) — malformed email address or header; ThrottlingException (400) — request rate too high (retryable); ServiceUnavailable (503) — AWS SES temporarily unavailable; NetworkError — connection failure, timeout, DNS resolution failure. All errors are subclasses of ServiceException; error name is in error.name.
    Required handlingMUST wrap await sesClient.send(new Send*Command(...)) in try-catch. Catch block SHOULD distinguish MessageRejected (permanent failure — do not retry), ThrottlingException / LimitExceededException (retryable — use exponential backoff), and AccountSendingPausedException (operational — alert on-call). For bulk/transactional email, a failed send should be surfaced to the caller, not silently swallowed.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][2][3]
  • SendTemplatedEmailCommand · ses-template-does-not-exist
    error
    WhensesClient.send(new SendTemplatedEmailCommand(...)) called with a Template name that does not exist in the SES account
    ThrowsTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. TemplateDoesNotExistException is thrown immediately when the template name is not found — the email is NOT sent. Catch block SHOULD log the template name to aid debugging. This error commonly occurs when templates are deleted or when code is deployed to a new AWS account/region without running the template setup step.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[4][5]
  • SendTemplatedEmailCommand · ses-template-rendering-failure-silent
    error
    WhensesClient.send(new SendTemplatedEmailCommand(...)) returns a MessageId successfully but the template contains rendering errors (missing partial, malformed Handlebars syntax, undefined helper)
    ReturnsAWS SES accepts the message and returns a 200 with a MessageId, but the email is NOT sent. Rendering failures are reported only via SNS event notifications (RenderingFailure event type) — NOT as an exception. This is a silent failure: the caller receives a successful response but the recipient never gets the email.
    Required handlingMUST configure SNS event notifications for RenderingFailure events on the configuration set. Do NOT assume a returned MessageId means the email was delivered — it only means SES accepted the request for processing. Validate TemplateData JSON matches all template variable names before sending.
    costhighin prodsilent failureusers seeservice unavailablevisibilitysilent
    Sources[4][6]
  • SendTemplatedEmailCommand · ses-template-missing-rendering-attribute
    error
    WhensesClient.send(new SendTemplatedEmailCommand(...)) called with TemplateData JSON that is missing one or more required template variable values that the template references
    ThrowsMissingRenderingAttributeException
    Required handlingMUST wrap in try-catch. MissingRenderingAttributeException is thrown at request time when TemplateData does not include all variables referenced in the template. Catch block SHOULD log the template name and the missing attribute names. Fix by ensuring TemplateData contains all required keys, or make template variables optional with defaults.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[4]
  • SendBulkTemplatedEmailCommand · ses-bulk-template-does-not-exist
    error
    WhensesClient.send(new SendBulkTemplatedEmailCommand(...)) called with a Template name that does not exist in the SES account
    ThrowsTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. TemplateDoesNotExistException fails the entire batch — no emails are sent. This is distinct from per-destination failures. Ensure the template exists in the target account/region before calling.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[7]
  • SendBulkTemplatedEmailCommand · ses-bulk-partial-destination-failure
    error
    WhensesClient.send(new SendBulkTemplatedEmailCommand(...)) succeeds overall (no exception thrown) but one or more individual destinations in the Destinations array fail (e.g., invalid address, blacklisted recipient, per-destination rendering failure)
    ReturnsAPI returns 200 with a SendBulkTemplatedEmailResponse. The response contains a Status array with one entry per destination. Each entry has a Status field ('Success' or failure message) and a MessageId (only set on success). Failed destinations have Status set to the failure reason. If the caller does not inspect the Status array, failed recipients are silently dropped.
    Required handlingMUST inspect the response.Status array after a successful API call. For each entry: if entry.Status !== 'Success', log the failure and consider requeuing that destination. Pattern: const response = await sesClient.send(new SendBulkTemplatedEmailCommand(...)); for (const result of response.Status) { if (result.Status !== 'Success') { logger.error('Bulk email failed for destination', { status: result.Status }); } }
    costhighin prodsilent failureusers seeservice unavailablevisibilitysilent
    Sources[7]
  • SendRawEmailCommand · ses-raw-email-size-limit
    error
    WhensesClient.send(new SendRawEmailCommand(...)) called with a message (including all attachments) that exceeds 10 MB total size
    ThrowsMessageRejected
    Required handlingMUST enforce a 10 MB total message size limit before calling SendRawEmail. The limit includes all headers, body, and attachment data after MIME encoding. Note that base64 encoding adds ~33% overhead — a 7.5 MB file becomes ~10 MB after encoding. Validate message size in application code before sending. For large attachments, use S3 pre-signed URLs in the email body instead.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8]
  • SendRawEmailCommand · ses-raw-email-recipient-limit
    error
    WhensesClient.send(new SendRawEmailCommand(...)) called with more than 50 total recipients combined across To:, Cc:, and Bcc: headers
    ThrowsMessageRejected
    Required handlingMUST split recipient lists exceeding 50 total recipients into separate SendRawEmail calls. The 50-recipient limit applies to the total across all recipient types combined. This limit is separate from the daily sending quota. Enforce this constraint in the caller before invoking.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8]
  • SendCustomVerificationEmailCommand · ses-custom-verification-template-missing
    error
    WhensesClient.send(new SendCustomVerificationEmailCommand(...)) called with a TemplateName that does not exist in the SES account
    ThrowsCustomVerificationEmailTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. Template must be created via CreateCustomVerificationEmailTemplate before this call. This error is common in new account setup or when templates are deleted. Catch block SHOULD log the template name and alert operators to recreate it.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • SendCustomVerificationEmailCommand · ses-custom-verification-sender-not-verified
    error
    WhensesClient.send(new SendCustomVerificationEmailCommand(...)) where the sender email address stored in the template is not verified in SES
    ThrowsFromEmailAddressNotVerifiedException
    Required handlingMUST ensure the sender email address (stored in the custom verification template, not the caller's input) is verified in SES before calling. This error occurs after template setup if the verified identity is deleted. Catch block SHOULD log the unverified sender address and alert operators.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • SendCustomVerificationEmailCommand · ses-custom-verification-sandbox-restriction
    error
    WhensesClient.send(new SendCustomVerificationEmailCommand(...)) called on an AWS account that has not been granted production access (account is still in SES sandbox)
    ThrowsProductionAccessNotGrantedException
    Required handlingIn sandbox mode, custom verification emails can only be sent to verified email addresses. ProductionAccessNotGrantedException is thrown when sending to unverified addresses in sandbox. Request production access through the AWS console before using this in production. In development/staging, either test with verified addresses or mock this call.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[9]
  • CreateTemplateCommand · ses-create-template-already-exists
    warning
    WhensesClient.send(new CreateTemplateCommand(...)) called with a TemplateName that already exists in the SES account
    ThrowsAlreadyExistsException
    Required handlingMUST wrap in try-catch. In idempotent deployment scripts, catch AlreadyExistsException and either skip (template already exists) or switch to UpdateTemplateCommand for updates. Do NOT let this exception fail a CI/CD deployment pipeline — it is a recoverable condition. Pattern: try { create } catch(AlreadyExistsException) { update instead }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[10]
  • CreateTemplateCommand · ses-create-template-invalid-syntax
    error
    WhensesClient.send(new CreateTemplateCommand(...)) called with a template whose HtmlPart/TextPart/SubjectPart contains invalid Handlebars syntax or refers to a partial that does not exist
    ThrowsInvalidTemplateException
    Required handlingMUST wrap in try-catch. InvalidTemplateException is thrown when the template syntax is malformed or references undefined partials. Catch block SHOULD log the template content to identify the invalid syntax. Validate template rendering locally with Handlebars.js before deploying to SES. Note: a valid template may still fail at send time if TemplateData is missing required variables.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10]
  • UpdateTemplateCommand · ses-update-template-not-found
    error
    WhensesClient.send(new UpdateTemplateCommand(...)) called with a TemplateName that does not exist in the SES account
    ThrowsTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. TemplateDoesNotExistException is thrown when the template to update does not exist. In idempotent deployment scripts, catch this and switch to CreateTemplateCommand instead. Pattern: try { update } catch(TemplateDoesNotExistException) { create instead }.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[11]
  • UpdateTemplateCommand · ses-update-template-invalid-syntax
    error
    WhensesClient.send(new UpdateTemplateCommand(...)) called with a template whose updated content contains invalid Handlebars syntax
    ThrowsInvalidTemplateException
    Required handlingMUST wrap in try-catch. InvalidTemplateException is thrown when the new template content is syntactically invalid. Previous template content is preserved — the update is atomic and does not partially apply. Validate template content locally with Handlebars.js before updating.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[11]
  • SendEmailCommand · ses-send-email-no-try-catch
    error
    WhensesClient.send(new SendEmailCommand(...)) called without a try-catch wrapping the await expression
    ThrowsMessageRejected (400) — message failed SES content policy, spam scoring, or blocklist; MailFromDomainNotVerifiedException (400) — custom MAIL FROM domain has broken DNS/MX record; AccountSendingPausedException (400) — sending paused at account level (billing/compliance); ConfigurationSetSendingPausedException (400) — sending disabled on the named config set; ConfigurationSetDoesNotExistException (400) — named configuration set not found; LimitExceededException (400) — 24-hour quota or per-second sending rate exceeded; ThrottlingException (400) — request rate too high, retryable. All errors are subclasses of SESServiceException; error name is in error.name.
    Required handlingMUST wrap await sesClient.send(new SendEmailCommand(...)) in try-catch. Catch block SHOULD distinguish MessageRejected (permanent — do not retry), AccountSendingPausedException (operational alert required), and LimitExceededException / ThrottlingException (retryable with backoff). Never silently swallow errors — the user is waiting for the email.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[12][2]
  • TestRenderTemplateCommand · ses-test-render-template-missing
    error
    WhensesClient.send(new TestRenderTemplateCommand(...)) called with a TemplateName that does not exist in the SES account
    ThrowsTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. TemplateDoesNotExistException is thrown at request time when the template name is not found. This is the first point of failure in deployment pipelines that validate templates before sending. Catch block SHOULD log the template name to aid debugging. Pattern: catch TemplateDoesNotExistException and fail the deployment or alert operators.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[13][14]
  • TestRenderTemplateCommand · ses-test-render-missing-attribute
    error
    WhensesClient.send(new TestRenderTemplateCommand(...)) called with TemplateData JSON that is missing one or more variable names referenced in the template
    ThrowsMissingRenderingAttributeException
    Required handlingMUST wrap in try-catch. MissingRenderingAttributeException is thrown when TemplateData does not include all variables the template references. Unlike SendTemplatedEmailCommand (which silently fails delivery), TestRenderTemplateCommand explicitly throws this error. Catch block SHOULD log missing attribute names and fix TemplateData before attempting to render or send.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[13][14]
  • TestRenderTemplateCommand · ses-test-render-invalid-parameter
    warning
    WhensesClient.send(new TestRenderTemplateCommand(...)) called with a TemplateData JSON object containing invalid values for one or more template variables (e.g., wrong type, null where a string is expected)
    ThrowsInvalidRenderingParameterException
    Required handlingMUST wrap in try-catch. InvalidRenderingParameterException is thrown when TemplateData values are of the wrong type or otherwise invalid. Catch block SHOULD log the invalid parameters from the error message. Validate TemplateData shape against the template variable list before calling.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[13][14]
  • CreateConfigurationSetCommand · ses-create-config-set-already-exists
    warning
    WhensesClient.send(new CreateConfigurationSetCommand(...)) called with a ConfigurationSet.Name that already exists in the SES account
    ThrowsConfigurationSetAlreadyExistsException
    Required handlingMUST wrap in try-catch. In idempotent deployment scripts, catch ConfigurationSetAlreadyExistsException and skip (the set already exists — this is a recoverable condition). Do NOT let this exception fail a CI/CD deployment. Pattern: try { create } catch(ConfigurationSetAlreadyExistsException) { skip }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[15][16]
  • CreateConfigurationSetCommand · ses-create-config-set-invalid
    error
    WhensesClient.send(new CreateConfigurationSetCommand(...)) called with a ConfigurationSet.Name containing invalid characters or exceeding length limits
    ThrowsInvalidConfigurationSetException
    Required handlingMUST wrap in try-catch. InvalidConfigurationSetException is thrown when the configuration set name is invalid. Names must be ASCII and conform to AWS naming constraints. Catch block SHOULD log the invalid name and correct it in the deployment configuration.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[15][16]
  • CreateConfigurationSetCommand · ses-create-config-set-limit-exceeded
    error
    WhensesClient.send(new CreateConfigurationSetCommand(...)) called when the AWS account has reached the maximum allowed number of configuration sets
    ThrowsLimitExceededException
    Required handlingMUST wrap in try-catch. LimitExceededException is thrown when the account has reached the SES configuration set limit. Catch block SHOULD log the error and alert operators to review and delete unused configuration sets. This limit is rarely hit in practice but can block deployment automation.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[15]
  • CreateConfigurationSetEventDestinationCommand · ses-event-dest-config-set-not-found
    error
    WhensesClient.send(new CreateConfigurationSetEventDestinationCommand(...)) called with a ConfigurationSetName that does not exist in the SES account
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when the configuration set specified by ConfigurationSetName does not exist. In deployment scripts, ensure CreateConfigurationSetCommand is called first (or catch ConfigurationSetAlreadyExistsException to confirm it exists). Catch block SHOULD log the missing configuration set name.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[17][18]
  • CreateConfigurationSetEventDestinationCommand · ses-event-dest-already-exists
    warning
    WhensesClient.send(new CreateConfigurationSetEventDestinationCommand(...)) called with an EventDestination.Name that already exists in the specified configuration set
    ThrowsEventDestinationAlreadyExistsException
    Required handlingMUST wrap in try-catch. EventDestinationAlreadyExistsException is thrown when a destination with the same name already exists. In idempotent deployment scripts, catch this and skip (destination already configured). Pattern: try { create } catch(EventDestinationAlreadyExistsException) { skip }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[17][18]
  • CreateConfigurationSetEventDestinationCommand · ses-event-dest-invalid-destination
    error
    WhensesClient.send(new CreateConfigurationSetEventDestinationCommand(...)) called with an EventDestination whose CloudWatch, Kinesis Firehose, or SNS configuration parameters are invalid (e.g., invalid ARN, IAM role lacks permissions, SNS topic in wrong region, CloudWatch dimension configuration invalid)
    ThrowsInvalidCloudWatchDestinationException — CloudWatch destination parameters invalid; InvalidFirehoseDestinationException — Kinesis Firehose ARN or IAM role invalid; InvalidSNSDestinationException — SNS topic ARN invalid or in wrong region.
    Required handlingMUST wrap in try-catch. Destination validation errors indicate misconfigured AWS resources (wrong ARNs, insufficient IAM permissions). These are deployment-time errors that prevent the event pipeline from being set up correctly. If not caught and the deployment proceeds, email events (bounces, complaints) will not be delivered to the monitoring destination — silent observability failure. Catch block SHOULD log the destination type and the specific error message from AWS.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[17][18]
  • CreateCustomVerificationEmailTemplateCommand · ses-create-cve-template-already-exists
    warning
    WhensesClient.send(new CreateCustomVerificationEmailTemplateCommand(...)) called with a TemplateName that already exists in the SES account
    ThrowsCustomVerificationEmailTemplateAlreadyExistsException
    Required handlingMUST wrap in try-catch. In idempotent deployment scripts, catch CustomVerificationEmailTemplateAlreadyExistsException and either skip or switch to UpdateCustomVerificationEmailTemplateCommand to update the content. Pattern: try { create } catch(TemplateAlreadyExists) { update instead }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[19][20]
  • CreateCustomVerificationEmailTemplateCommand · ses-create-cve-template-invalid-content
    error
    WhensesClient.send(new CreateCustomVerificationEmailTemplateCommand(...)) called with TemplateContent that exceeds 10 MB or contains invalid HTML structure
    ThrowsCustomVerificationEmailInvalidContentException
    Required handlingMUST wrap in try-catch. CustomVerificationEmailInvalidContentException is thrown when the template content is too large or structurally invalid. Catch block SHOULD log the template name and validate content size and HTML validity before retrying.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[19][20]
  • CreateCustomVerificationEmailTemplateCommand · ses-create-cve-template-from-not-verified
    error
    WhensesClient.send(new CreateCustomVerificationEmailTemplateCommand(...)) called with a FromEmailAddress that has not been verified in SES
    ThrowsFromEmailAddressNotVerifiedException
    Required handlingMUST wrap in try-catch. FromEmailAddressNotVerifiedException is thrown when the FromEmailAddress is not an SES-verified identity. The template is NOT created. Verify the sender address in SES before calling this command. Catch block SHOULD log the unverified address and alert operators.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[19][20]
  • UpdateCustomVerificationEmailTemplateCommand · ses-update-cve-template-not-found
    error
    WhensesClient.send(new UpdateCustomVerificationEmailTemplateCommand(...)) called with a TemplateName that does not exist in the SES account
    ThrowsCustomVerificationEmailTemplateDoesNotExistException
    Required handlingMUST wrap in try-catch. CustomVerificationEmailTemplateDoesNotExistException is thrown when the template to update does not exist. In idempotent deployment scripts, catch this and switch to CreateCustomVerificationEmailTemplateCommand. Pattern: try { update } catch(TemplateDoesNotExist) { create instead }.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[21][22]
  • UpdateCustomVerificationEmailTemplateCommand · ses-update-cve-template-invalid-content
    error
    WhensesClient.send(new UpdateCustomVerificationEmailTemplateCommand(...)) called with updated TemplateContent that exceeds 10 MB or contains invalid HTML
    ThrowsCustomVerificationEmailInvalidContentException
    Required handlingMUST wrap in try-catch. CustomVerificationEmailInvalidContentException is thrown when the updated content is too large or invalid. Previous template content is preserved — the update does not partially apply. Catch block SHOULD validate content size and HTML structure before retrying.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[21][22]
  • UpdateCustomVerificationEmailTemplateCommand · ses-update-cve-template-from-not-verified
    error
    WhensesClient.send(new UpdateCustomVerificationEmailTemplateCommand(...)) called with a new FromEmailAddress that has not been verified in SES
    ThrowsFromEmailAddressNotVerifiedException
    Required handlingMUST wrap in try-catch. FromEmailAddressNotVerifiedException is thrown when the updated FromEmailAddress is not a verified SES identity. The update is NOT applied. Catch block SHOULD log the unverified address and ensure the new sender identity is verified before retrying the update.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[21][22]
  • SendBounceCommand · ses-send-bounce-no-try-catch
    error
    WhensesClient.send(new SendBounceCommand(...)) called without try-catch in an inbound email processing handler
    ThrowsMessageRejected
    Required handlingMUST wrap in try-catch. MessageRejected is thrown when the bounce cannot be sent — e.g., the BounceSender is not a verified SES identity, the OriginalMessageId is invalid or older than 24 hours, or the request fails validation. Bounce pipelines commonly omit error handling because SendBounce is a "fire and forget" side effect — but an unhandled MessageRejected will crash the inbound email handler and stop processing subsequent messages. Catch block SHOULD log the failed bounce and continue processing other messages.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[23][24]
  • SendBounceCommand · ses-send-bounce-stale-message-id
    warning
    WhensesClient.send(new SendBounceCommand({ OriginalMessageId: staleId, ... })) where staleId refers to a message received more than 24 hours ago
    ThrowsMessageRejected
    Required handlingMUST validate message age before calling SendBounceCommand. The 24-hour constraint is strict — SES rejects bounce requests for messages older than 24 hours with MessageRejected. Queued bounce jobs that are delayed (e.g., by a slow SQS consumer) will silently lose the ability to send compliant DSNs. Catch block SHOULD distinguish stale-message rejections from sender-not-verified rejections. Log with the original message timestamp for debugging.
    costlowin prodimmediate exceptionusers seelost datavisibilitysilent
    Sources[24]
  • UpdateConfigurationSetEventDestinationCommand · ses-update-event-dest-config-set-not-found
    error
    WhensesClient.send(new UpdateConfigurationSetEventDestinationCommand({ ConfigurationSetName: name, ... })) where name references a configuration set that does not exist
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when the named configuration set has been deleted or was never created. Infrastructure provisioning scripts that update event destinations without verifying config set existence will crash on first run in a fresh environment. Catch block SHOULD attempt to create the configuration set first, then retry.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[25][26]
  • UpdateConfigurationSetEventDestinationCommand · ses-update-event-dest-not-found
    error
    WhensesClient.send(new UpdateConfigurationSetEventDestinationCommand({ ..., EventDestination: { Name: destName } })) where destName references an event destination that does not exist in the config set
    ThrowsEventDestinationDoesNotExistException
    Required handlingMUST wrap in try-catch. EventDestinationDoesNotExistException is thrown when attempting to update a named event destination that doesn't exist in the configuration set. Idempotent infrastructure scripts must catch this and switch to CreateConfigurationSetEventDestinationCommand. Pattern: try { update } catch(EventDestinationDoesNotExist) { create instead }.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[25]
  • UpdateConfigurationSetEventDestinationCommand · ses-update-event-dest-invalid-destination
    error
    WhensesClient.send(new UpdateConfigurationSetEventDestinationCommand({ ..., EventDestination: { CloudWatchDestination: invalidConfig } })) or similar with an invalid Firehose or SNS destination configuration
    ThrowsInvalidCloudWatchDestinationException
    Required handlingMUST wrap in try-catch. InvalidCloudWatchDestinationException, InvalidFirehoseDestinationException, or InvalidSNSDestinationException are thrown when the destination configuration is structurally invalid (wrong ARN format, missing required fields, insufficient IAM permissions for SES to write to the destination). Exactly one destination type must be configured. Catch block SHOULD log the specific error type and the destination ARN that was invalid to aid debugging.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[25][26]
  • PutConfigurationSetDeliveryOptionsCommand · ses-put-delivery-options-config-set-not-found
    error
    WhensesClient.send(new PutConfigurationSetDeliveryOptionsCommand({ ConfigurationSetName: name, ... })) where name references a configuration set that does not exist
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when the named configuration set has been deleted or never created. Security hardening scripts that configure TLS policies during deployment will crash if the configuration set was not provisioned first. Catch block SHOULD first create the configuration set, then retry PutConfigurationSetDeliveryOptionsCommand.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[27][28]
  • PutConfigurationSetDeliveryOptionsCommand · ses-put-delivery-options-invalid
    error
    WhensesClient.send(new PutConfigurationSetDeliveryOptionsCommand({ ..., DeliveryOptions: { TlsPolicy: invalidValue } })) with an invalid TlsPolicy value or malformed DeliveryOptions
    ThrowsInvalidDeliveryOptionsException
    Required handlingMUST wrap in try-catch. InvalidDeliveryOptionsException is thrown when the provided TlsPolicy value is not one of "Require" or "Optional", or when the DeliveryOptions object is otherwise malformed. TypeScript types prevent this at compile time, but runtime-constructed inputs (e.g., from environment variables or API parameters) can still trigger this. Catch block SHOULD validate TlsPolicy against the known enum values before calling the command.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[27]
  • DeleteConfigurationSetCommand · ses-delete-config-set-not-found
    error
    WhensesClient.send(new DeleteConfigurationSetCommand({ ConfigurationSetName: name })) where name references a configuration set that does not exist
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when attempting to delete a configuration set that was already deleted or never created. Unlike S3 object deletion, SES config set deletion is NOT idempotent — calling it twice throws on the second call. Cleanup scripts and test teardown code that unconditionally call DeleteConfigurationSetCommand will throw on re-runs. Catch block SHOULD either check existence first with DescribeConfigurationSet, or catch ConfigurationSetDoesNotExistException and treat it as a success (already deleted).
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[29][30]
  • CreateReceiptRuleSetCommand · ses-create-receipt-rule-set-already-exists
    warning
    WhensesClient.send(new CreateReceiptRuleSetCommand({ RuleSetName: name })) called with a RuleSetName that already exists in the SES account
    ThrowsAlreadyExistsException
    Required handlingMUST wrap in try-catch. AlreadyExistsException is thrown when a receipt rule set with the same name already exists. In idempotent deployment scripts, catch this and skip (rule set already exists — this is recoverable). Do NOT let this exception fail a CI/CD deployment pipeline. Pattern: try { create } catch(AlreadyExistsException) { skip or verify rules }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[31][32]
  • CreateReceiptRuleSetCommand · ses-create-receipt-rule-set-limit-exceeded
    error
    WhensesClient.send(new CreateReceiptRuleSetCommand(...)) called when the AWS account has reached the maximum number of receipt rule sets
    ThrowsLimitExceededException
    Required handlingMUST wrap in try-catch. LimitExceededException is thrown when the account's receipt rule set quota is exhausted. Catch block SHOULD log the error and alert operators to review and remove unused rule sets. This limit blocks deployment automation and prevents inbound email routing from being configured in new environments.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[31][32]
  • CreateReceiptRuleCommand · ses-create-receipt-rule-invalid-action-config
    error
    WhensesClient.send(new CreateReceiptRuleCommand({ ..., Rule: { Actions: [{ LambdaAction: { FunctionArn: invalidArn }, S3Action: { BucketName: badBucket }, or SNSAction: { TopicArn: invalidTopic } }] } })) where any action target is invalid, does not exist, or lacks the required IAM permissions for SES
    ThrowsInvalidLambdaFunctionException — Lambda ARN is invalid, function does not exist, or SES lacks invoke permissions on the function; InvalidS3ConfigurationException — S3 bucket does not exist, is in a different region, lacks a bucket policy granting SES PutObject permission, or the KMS key is invalid; InvalidSnsTopicException — SNS topic ARN is invalid, topic does not exist, or SES lacks Publish permission on the topic.
    Required handlingMUST wrap in try-catch. These exceptions are thrown at rule-creation time, not at email-receipt time — a misconfigured action is rejected before the rule takes effect. This is an early-detection safety mechanism. Catch block SHOULD log the specific exception type to identify which action target (Lambda/S3/SNS) has the configuration problem, and fix IAM permissions before retrying. These errors commonly occur when deploying to a new AWS account or region where SES resource-based policies have not been set up.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[33][34]
  • CreateReceiptRuleCommand · ses-create-receipt-rule-ruleset-not-found
    error
    WhensesClient.send(new CreateReceiptRuleCommand({ RuleSetName: name, ... })) where name references a receipt rule set that does not exist
    ThrowsRuleSetDoesNotExistException
    Required handlingMUST wrap in try-catch. RuleSetDoesNotExistException is thrown when the specified RuleSetName does not exist. Deployment scripts that add rules to a rule set must ensure the rule set was created first (via CreateReceiptRuleSetCommand). Catch block SHOULD attempt to create the rule set first, then retry adding the rule.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[33][34]
  • CreateReceiptRuleCommand · ses-create-receipt-rule-already-exists
    warning
    WhensesClient.send(new CreateReceiptRuleCommand({ ..., Rule: { Name: ruleName } })) called with a Rule.Name that already exists in the specified rule set
    ThrowsAlreadyExistsException
    Required handlingMUST wrap in try-catch. AlreadyExistsException is thrown when a rule with the same name already exists in the rule set. In idempotent deployment scripts, catch this and skip or switch to UpdateReceiptRuleCommand to update the existing rule. Do NOT fail the deployment — the rule already exists.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[33]
  • SetActiveReceiptRuleSetCommand · ses-set-active-receipt-rule-set-not-found
    error
    WhensesClient.send(new SetActiveReceiptRuleSetCommand({ RuleSetName: name })) where name references a receipt rule set that does not exist in the account
    ThrowsRuleSetDoesNotExistException
    Required handlingMUST wrap in try-catch. RuleSetDoesNotExistException is thrown when the specified RuleSetName does not exist. Deployment scripts that activate a rule set after creating it must handle this in case the creation step failed or the name is misspelled. When this exception is thrown, the previously active rule set remains active — inbound email routing is NOT disrupted, but the intended new routing is not applied. Catch block SHOULD log the missing rule set name and alert operators. Never silently swallow this error — it means inbound email routing was NOT switched as intended.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[35][36]
  • CreateConfigurationSetTrackingOptionsCommand · ses-create-tracking-options-invalid-domain
    error
    WhensesClient.send(new CreateConfigurationSetTrackingOptionsCommand({ ConfigurationSetName: name, TrackingOptions: { CustomRedirectDomain: domain } })) where domain is not verified in SES or is not a valid domain/subdomain
    ThrowsInvalidTrackingOptionsException
    Required handlingMUST wrap in try-catch. InvalidTrackingOptionsException is thrown when the CustomRedirectDomain is not a verified SES identity or is not a valid domain format. This error is distinct from the configuration set not existing. Catch block SHOULD log the invalid domain and alert operators to verify it in SES first (via VerifyDomainIdentityCommand). Email opens and clicks will NOT be tracked until tracking options are correctly configured.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[37][38]
  • CreateConfigurationSetTrackingOptionsCommand · ses-create-tracking-options-already-exists
    warning
    WhensesClient.send(new CreateConfigurationSetTrackingOptionsCommand(...)) called on a configuration set that already has a TrackingOptions object
    ThrowsTrackingOptionsAlreadyExistsException
    Required handlingMUST wrap in try-catch. TrackingOptionsAlreadyExistsException is thrown when a TrackingOptions object already exists on the specified configuration set — only one is allowed per set. In idempotent deployment scripts, catch this and either skip or switch to UpdateConfigurationSetTrackingOptionsCommand to modify the existing tracking domain. Pattern: try { create } catch(TrackingOptionsAlreadyExistsException) { update instead }.
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[37][38]
  • CreateConfigurationSetTrackingOptionsCommand · ses-create-tracking-options-config-set-not-found
    error
    WhensesClient.send(new CreateConfigurationSetTrackingOptionsCommand({ ConfigurationSetName: name, ... })) where name does not exist
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. Deployment scripts that add tracking options to a configuration set must ensure the configuration set was created first. Catch block SHOULD create the configuration set, then retry.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[37]
  • UpdateConfigurationSetSendingEnabledCommand · ses-update-config-set-sending-enabled-not-found
    error
    WhensesClient.send(new UpdateConfigurationSetSendingEnabledCommand({ ConfigurationSetName: name, Enabled: false })) where name does not exist, typically in an automated CloudWatch → Lambda → SES reputation protection pipeline that references a hardcoded or environment-variable-sourced config set name
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when the named configuration set does not exist. This is critical in automated reputation management pipelines — if the exception is unhandled, the Lambda function crashes without pausing email sending, allowing bounce and complaint rates to continue accumulating and potentially triggering an AWS account-level sending suspension. Catch block MUST alert on-call — failed reputation protection is a SEV-1 incident risk. Log the configuration set name and verify it exists in the target AWS account/region.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[39][40]
  • PutIdentityPolicyCommand · ses-put-identity-policy-invalid
    error
    WhensesClient.send(new PutIdentityPolicyCommand({ Identity: identity, PolicyName: name, Policy: policyJson })) where policyJson is malformed JSON, exceeds 4 KB, has invalid IAM principals or actions, or does not conform to SES authorization policy syntax
    ThrowsInvalidPolicyException
    Required handlingMUST wrap in try-catch. InvalidPolicyException is thrown when the policy document is syntactically invalid, structurally invalid, or exceeds the 4 KB size limit. The policy is NOT applied — the previous policy (if any) is preserved. In multi-tenant SaaS applications where customers configure sending authorization policies, an unhandled InvalidPolicyException will crash the provisioning endpoint, leaving the customer unable to send email through the platform. Catch block SHOULD extract the specific policy error from the exception message (AWS includes details about what is invalid) and return a meaningful error to the caller. Validate policy JSON structure and size before calling.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[41][42]
  • DeleteConfigurationSetEventDestinationCommand · ses-delete-event-dest-not-found
    error
    WhensesClient.send(new DeleteConfigurationSetEventDestinationCommand({ ConfigurationSetName: csName, EventDestinationName: destName })) where destName does not exist in the specified configuration set
    ThrowsEventDestinationDoesNotExistException
    Required handlingMUST wrap in try-catch. EventDestinationDoesNotExistException is thrown when the destination name does not exist in the configuration set. Unlike S3 object deletion, SES event destination deletion is NOT idempotent — calling it twice throws on the second call. Cleanup scripts and test teardown code that unconditionally delete event destinations will throw on re-runs. Catch block SHOULD either check existence first with DescribeConfigurationSet, or catch EventDestinationDoesNotExistException and treat as success (already deleted). Log the missing destination name for audit purposes.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[43][44]
  • DeleteConfigurationSetEventDestinationCommand · ses-delete-event-dest-config-set-not-found
    error
    WhensesClient.send(new DeleteConfigurationSetEventDestinationCommand({ ConfigurationSetName: csName, ... })) where csName does not exist
    ThrowsConfigurationSetDoesNotExistException
    Required handlingMUST wrap in try-catch. ConfigurationSetDoesNotExistException is thrown when the parent configuration set does not exist. Cleanup scripts that tear down an entire SES configuration (config set + event destinations) must handle both the case where the config set is already gone and where only specific destinations are missing.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[43]
  • CloneReceiptRuleSetCommand · ses-clone-receipt-rule-set-already-exists
    error
    WhensesClient.send(new CloneReceiptRuleSetCommand({ RuleSetName: target, OriginalRuleSetName: source })) where target already exists in the account
    ThrowsAlreadyExistsException
    Required handlingMUST wrap in try-catch. AlreadyExistsException is thrown when the destination RuleSetName already exists in the SES account. Provisioning scripts that re-run after a partial failure will throw on the second run because cloning is NOT idempotent. The clone is NOT applied — the existing rule set is preserved unchanged. Catch block SHOULD distinguish AlreadyExistsException (already provisioned, safe to skip) from LimitExceededException (hit SES rule-set quota, requires a quota increase request) and from RuleSetDoesNotExistException (typo in source name, requires operator intervention). Idempotent provisioning scripts should treat AlreadyExistsException as success and verify the existing rule set matches expectations with DescribeReceiptRuleSet.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[45][46]
  • CloneReceiptRuleSetCommand · ses-clone-receipt-rule-set-source-not-found
    error
    WhensesClient.send(new CloneReceiptRuleSetCommand({ RuleSetName: target, OriginalRuleSetName: source })) where source does not exist
    ThrowsRuleSetDoesNotExistException
    Required handlingMUST wrap in try-catch. RuleSetDoesNotExistException is thrown when the OriginalRuleSetName does not exist. The clone is NOT applied. Common in environment-promotion scripts that hardcode a source rule set name that has been renamed or deleted in the source environment. Catch block SHOULD log the missing source name and either fail loudly or fall back to creating the rule set from scratch with CreateReceiptRuleSet. Do NOT silently swallow — inbound mail receipt rules are security-critical and a missing rule set means inbound mail is being processed by a different (possibly default) rule set.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[45][46]
  • CreateReceiptFilterCommand · ses-create-receipt-filter-already-exists
    error
    WhensesClient.send(new CreateReceiptFilterCommand({ Filter: { Name: name, IpFilter: { Cidr: cidr, Policy: 'Block' | 'Allow' } } })) where Filter.Name already exists in the account
    ThrowsAlreadyExistsException
    Required handlingMUST wrap in try-catch. AlreadyExistsException is thrown when a filter with the same Name already exists. The new filter is NOT applied — the existing filter (which may have a DIFFERENT CIDR or Policy) is preserved. This is a security hazard: a provisioning script that intends to BLOCK a new CIDR may silently fail and leave the existing ALLOW filter in place, allowing abuse traffic through. Catch block SHOULD distinguish AlreadyExistsException (verify the existing filter matches expected CIDR + Policy via ListReceiptFilters; if not, delete and recreate) from LimitExceededException (hit 100-filter quota, requires consolidation or quota increase). NEVER silently treat AlreadyExistsException as success without verifying the existing filter.
    costmediumin prodimmediate exceptionusers seesecurity breachvisibilityvisible
    Sources[47][48]
  • CreateReceiptFilterCommand · ses-create-receipt-filter-limit-exceeded
    error
    WhensesClient.send(new CreateReceiptFilterCommand({ Filter: { Name: name, IpFilter: {...} } })) when account already has 100 filters
    ThrowsLimitExceededException
    Required handlingMUST wrap in try-catch. LimitExceededException is thrown when the account quota of 100 receipt filters has been reached. Automated abuse-mitigation systems that add a filter per blocked IP will hit this limit and start silently failing if the exception is swallowed, leaving new abusive CIDRs unblocked. Catch block SHOULD trigger consolidation (merge contiguous CIDRs into larger blocks via summarization) or escalate to an operator. Log the attempted filter name and CIDR so the gap is visible in audit trails.
    costmediumin prodimmediate exceptionusers seesecurity breachvisibilityvisible
    Sources[47][48]
  • UpdateReceiptRuleCommand · ses-update-receipt-rule-invalid-action-config
    error
    WhensesClient.send(new UpdateReceiptRuleCommand({ RuleSetName, Rule: { Actions: [{ LambdaAction | S3Action | SNSAction: {...} }] } })) where the Lambda ARN, S3 bucket, or SNS topic is invalid or SES lacks permission to invoke/write/publish
    ThrowsInvalidLambdaFunctionException | InvalidS3ConfigurationException | InvalidSnsTopicException
    Required handlingMUST wrap in try-catch. Each of these exceptions is thrown when the corresponding action target is misconfigured: InvalidLambdaFunctionException (Lambda ARN does not exist or SES service principal lacks lambda:InvokeFunction), InvalidS3ConfigurationException (S3 bucket missing, in wrong region, or lacks a bucket policy granting ses.amazonaws.com PutObject), InvalidSnsTopicException (SNS topic ARN invalid or missing permission). The rule is NOT updated — the previous (working or not) version is preserved. For an in-place rule update during incident response (e.g. switching the target Lambda after a function rename), an unhandled exception leaves the rule pointing at the OLD target. Inbound mail continues to flow to the deprecated function (which may have been deleted), causing silent mail loss. Catch block SHOULD validate action targets BEFORE calling UpdateReceiptRule (Lambda GetFunction, S3 HeadBucket + GetBucketPolicy, SNS GetTopicAttributes) and surface a clear error to the operator describing which action failed.
    costhighin prodimmediate exceptionusers seelost datavisibilityvisible
  • UpdateReceiptRuleCommand · ses-update-receipt-rule-not-found
    error
    WhensesClient.send(new UpdateReceiptRuleCommand({ RuleSetName: rsName, Rule: { Name: ruleName, ... } })) where ruleName does not exist in rsName, or rsName itself does not exist
    ThrowsRuleDoesNotExistException | RuleSetDoesNotExistException
    Required handlingMUST wrap in try-catch. UpdateReceiptRule does NOT create missing rules (use CreateReceiptRule for that). When the named rule or rule set is gone (e.g. another operator deleted it, or the script is running against the wrong AWS region), the exception leaves the inbound mail processing pipeline in its prior state — usually the disposition is unchanged but the operator BELIEVES they updated it. Catch block SHOULD distinguish RuleDoesNotExistException (rule was deleted — fall back to CreateReceiptRule with the same params) from RuleSetDoesNotExistException (whole rule set is gone — escalate to operator, do not auto-create). Log the names so the divergence is auditable.
    costmediumin prodimmediate exceptionusers seelost datavisibilityvisible
    Sources[49][50]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources: @aws-sdk/client-ses

All behavioral claims in contract.yaml are derived from the following sources.


Official AWS Documentation

SDK v3 SES Client Reference

SES API Reference — SendEmail

SES API Reference — SendRawEmail

SES API Reference — SendTemplatedEmail

SES API Reference — SendBulkTemplatedEmail

SES Common Errors

SES Developer Guide — Error Handling


SDK v3 Error Handling Pattern

AWS SDK v3 errors inherit from ServiceException (package @smithy/smithy-client). The error code / type is in error.name (not error.code as in SDK v2).

try {
  await sesClient.send(new SendEmailCommand(params));
} catch (err) {
  if (err instanceof Error) {
    switch (err.name) {
      case 'MessageRejected':
        // Permanent failure — do not retry
        break;
      case 'ThrottlingException':
      case 'LimitExceededException':
        // Retryable — use exponential backoff
        break;
      case 'AccountSendingPausedException':
        // Operational — alert on-call
        break;
    }
  }
}

Source: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/error-handling.html


Real-World Evidence

nocodb (16k+ stars)

  • File: packages/nocodb/src/plugins/ses/SES.ts
  • Pattern: nodemailer transport (SES as SESClient alias). Indirect usage through nodemailer wrapper.
  • Observation: Error handling is delegated to nodemailer callback (if (err) console.log(err)). Silent on send failure if callback not checked.

documenso (uses @aws-sdk/client-sesv2 for domain management)

  • Note: Modern SaaS apps are migrating to @aws-sdk/client-sesv2. This v1 contract covers existing codebases.

Package Notes

  • SES v1 vs v2: @aws-sdk/client-ses wraps the Amazon SES v1 API. @aws-sdk/client-sesv2 wraps the SES v2 API with additional features (contact lists, virtual deliverability manager). For new projects, AWS recommends SES v2. This contract covers the v1 client.
  • SDK v3 command pattern: Unlike SDK v2 (where methods like ses.sendEmail() were on the service object directly), SDK v3 requires sesClient.send(new SendEmailCommand({})). This contract covers the SDK v3 pattern.
  • Aggregate SES class: @aws-sdk/client-ses also exports an aggregate SES class with all commands as direct methods (e.g., ses.sendEmail()). This provides SDK v2-like ergonomics. This contract currently covers only the SESClient.send() pattern. The SES.sendEmail() pattern would require a separate function contract.
Need a different package?
Request a profile