Skip to main content

MailerSend Send ExecModule

Overview

MailersendSendModule submits one asynchronous transactional email to MailerSend's fixed https://api.mailersend.com/v1/email endpoint. Version 2.0 replaces the legacy batch sender with a narrow, verifiable contract: one recipient, one explicitly confirmed provider request, one READY IntegrationAccount, bounded content, and one validated x-message-id response header.

The former version accepted server-environment credentials and caller-controlled endpoints, silently changed missing credentials into a dry run, counted dry runs as successful delivery, retried non-idempotent sends, permitted unbounded batches and concurrency, and copied recipient and provider error details into logs and workflow output. Those behaviors are removed. Existing workflows that provide mailItems, raw credentials, an endpoint, dryRun, concurrency, retries, attachments, metadata, variables, tags, scheduled sends, or templates must migrate to the v2 single-message contract or a separately governed module that explicitly supports that feature.

Email submission is an external, non-idempotent side effect. The module never automatically retries an HTTP, timeout, or ambiguous transport failure because MailerSend may have accepted the message before ValkyrAI observed the failure.

Usage

  1. Verify the sending domain in MailerSend.
  2. Create a MailerSend API token with email sending permission.
  3. Store the token only in the encrypted apiKey field of a ValkyrAI IntegrationAccount, set the account status to READY, and bind it through ExecModuleConfig.authConfig.integrationAccount.
  4. Add MailersendSendModule to an approved outbound workflow.
  5. Supply one to address, one verified from address, a subject, and text or html.
  6. Set confirmSend to true only after the workflow has resolved the recipient, content, and required approval.
  7. Persist messageId and sendPaused for provider-console or Messages API reconciliation.

Inputs

NameTypeRequiredDescriptionLocal constraints
tostringYesSingle transactional recipient.Valid email, at most 254 characters.
toNamestringNoRecipient display name.At most 128 Unicode code points; no control characters, comma, or semicolon.
fromstringYesVerified MailerSend sender.Valid email, at most 254 characters.
fromNamestringNoSender display name.At most 128 Unicode code points; no control characters, comma, or semicolon.
replyTostringNoReply-to address.Valid email, at most 254 characters.
subjectstringYesMessage subject.Non-blank, at most 998 Unicode code points; no control characters.
textstringConditionalPlain-text body.text or html is required; at most 2 MB UTF-8.
htmlstringConditionalHTML body.html or text is required; at most 2 MB UTF-8.
confirmSendbooleanYesExplicit approval of the provider side effect.Must be the JSON boolean true.

Input-map values override the same normalized payload fields. The complete serialized provider request is limited to 4 MB. A body may contain newlines but not a null character.

The following legacy or unsafe fields are rejected before transport: mailItems, concurrency, retries, dryRun, mock, test, apiKey, api_key, token, secret, password, endpoint, url, attachments, metadata, variables, tags, sendAt, and templateId.

Outputs

NameTypeWhen presentDescription
statusstringAlwayssuccess only after verified acceptance; otherwise error.
messageIdstringSuccessOne bounded value from the x-message-id response header.
providerAcceptedbooleanAlwaysTrue only for HTTP 202 with one valid message ID.
sendPausedbooleanSuccessTrue when MailerSend also returns x-send-paused: true.
attemptsintegerAlways0 before transport or 1 after the single provider attempt.
errorobjectFailureSafe code, message, and retryable:false.

providerAccepted:true means MailerSend accepted the asynchronous request. It does not prove final delivery, inbox placement, reading, or link interaction. A paused send is accepted but not yet dispatched. The module does not return recipient data, message content, the API token, or the provider response body.

IntegrationAccount Requirements

SettingRequirement
ProviderMailerSend Email API
StatusREADY
AuthenticationBearer API token with email sending permission
accountNameHuman-readable MailerSend account or verified-domain identity
apiKeyEncrypted token, 20 to 4,096 non-whitespace characters
RelationshipBind through ExecModuleConfig.authConfig.integrationAccount

The module does not read MAILERSEND_API_KEY, MAILERSEND_API_ENDPOINT, alternate IntegrationAccount fields, workflow payload credentials, or caller-supplied URLs. It can contact only api.mailersend.com in production. Domain verification, suppression lists, unsubscribe policy, retention, and account compliance remain provider and tenant responsibilities.

Configuration

Illustrative normalized configuration:

{
"version": "2.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:mailersend-transactional"
},
"payloadConfig": {
"parameters": "{\"to\":\"customer@example.com\",\"toName\":\"Customer\",\"from\":\"billing@example.com\",\"fromName\":\"Valkyr Billing\",\"replyTo\":\"support@example.com\",\"subject\":\"Your account is ready\",\"text\":\"Setup is complete.\",\"confirmSend\":true}"
}
}

The account value is a symbolic secure reference. Persisted workflows use the generated IntegrationAccount relationship and never a plaintext token.

Operations

MailersendSendModule supports one operation:

Provider requestLocal behaviorSide effect
POST /v1/email on the fixed MailerSend originConstruct one bounded transactional message and verify the acceptance headers.Submits one asynchronous email to one recipient.

The request uses Authorization: Bearer and Content-Type: application/json. A provider response is successful only when the status is exactly 202 and x-message-id contains one safe, bounded identifier. x-send-paused: true is preserved in sendPaused rather than treated as final dispatch.

Bulk email, multiple recipients, cc/bcc, templates, personalization, attachments, tags, scheduled delivery, tracking settings, custom headers, contact management, delivery webhooks, and suppression management are outside this module's contract.

Errors and Failure Modes

FailureBehaviorRecovery
Validation failureReturns VALIDATION_ERROR before transport.Correct the named field and repeat approval.
Missing accountReturns INTEGRATION_ACCOUNT_REQUIRED.Bind the intended MailerSend account.
Non-ready accountReturns INTEGRATION_ACCOUNT_NOT_READY.Repair or reauthorize the account and set it to READY.
Invalid account tokenReturns VALIDATION_ERROR without sending.Rotate and store a bounded API token in apiKey.
HTTP 401 or 403Returns the matching MAILERSEND_HTTP_* code after one attempt.Rotate the token or repair email permission.
HTTP 422Returns MAILERSEND_HTTP_422 without provider body data.Verify sender domain, addresses, and required fields.
HTTP 429Returns MAILERSEND_HTTP_429 without retry.Reconcile provider activity and schedule a deliberate later attempt.
HTTP 5xx or transport failureReturns a safe ambiguous-acceptance failure without retry.Check MailerSend activity before any new send.
Oversized responseReturns MAILERSEND_RESPONSE_TOO_LARGE.Inspect provider compatibility; the body is not retained.
HTTP 202 without a safe IDReturns MAILERSEND_UNVERIFIED_ACCEPTANCE.Inspect MailerSend activity before retrying.

Provider bodies can contain recipient data or credential-like strings, so they are never copied into workflow output. Exceptions expose only bounded local guidance and the HTTP code when known.

Example

Submit one approved account notice:

{
"to": "customer@example.com",
"toName": "Customer",
"from": "billing@example.com",
"fromName": "Valkyr Billing",
"replyTo": "support@example.com",
"subject": "Your account is ready",
"text": "Setup is complete.",
"confirmSend": true
}

Expected result after MailerSend returns HTTP 202 and x-message-id:

{
"status": "success",
"messageId": "5e42957d51f1d94a1070a733",
"providerAccepted": true,
"sendPaused": false,
"attempts": 1
}

Notes

  • Pagination: not applicable; one execution submits one message.
  • Limits: one recipient, one request, 998 subject code points, 2 MB per body representation, and a 4 MB serialized request.
  • Rate limits: HTTP 429 is surfaced without automatic replay.
  • Idempotency: sending email is non-idempotent. confirmSend proves explicit workflow intent but is not a durable provider idempotency key.
  • API constraints: the production origin is fixed. Workflow input cannot select the bulk, template, scheduled, or alternate endpoint.
  • Suppression: a 202 response without x-message-id, including an all-suppressed response, is not claimed as accepted by this module.
  • Destructive behavior: the module cannot recall or compensate a message after provider acceptance.
  • Migration: replace each legacy mailItems batch with one governed task per recipient. Remove environment credentials, endpoints, concurrency, retries, and dry-run assumptions.
  • Observability: logs record only a validated message ID or failure class. Recipient addresses, subjects, bodies, tokens, and provider error bodies are omitted.
  • Unverified boundary: repository tests cover request construction, account requirements, validation, fixed routing, success-header verification, secret redaction, metadata discovery, and the single-attempt rule. Live sending requires separately authorized MailerSend credentials and is not exercised in repository tests.

See MailerSend's official Sending an Email reference for current request fields, the asynchronous 202 contract, x-message-id, paused sends, and suppression behavior.