Skip to main content

Email Recipients ExecModule

Overview

EmailRecipientsModule is a local audience-selection step for email workflows. Version 2.0 replaces an undocumented config-only implementation that exposed no input schema and converted malformed data into an empty result. The module now validates a bounded recipient array, requires optIn: true, normalizes addresses, suppresses case-insensitive duplicates, removes unapproved fields, and returns explicit safe failures.

The module does not send email. Connect its recipients output to a separately configured provider module such as SendGrid, Gmail, or Microsoft Outlook only after the workflow has applied its required content, approval, frequency, and suppression policies.

Usage

  1. Add Email Recipients before the provider-specific email module.
  2. Provide recipients either as the static recipients configuration or as the runtime recipients input.
  3. Ensure every eligible recipient has a valid email and the literal Boolean value optIn: true.
  4. Review the configured maxRecipients bound.
  5. Map the returned recipients array into the downstream delivery step.
  6. Treat excludedCount as a data-quality signal, not as delivery proof.

When a non-empty configured array is present, it takes precedence over runtime input. This makes the selected source deterministic and prevents an incoming workflow value from silently extending a reviewed static audience.

Inputs

InputTypeRequiredDescriptionConstraints
recipientsarrayConditionalRuntime recipient objects. Used only when static configuration is absent or empty.At most maxRecipients; every entry must be an object.

Each recipient object supports only these output fields:

FieldTypeRequired for eligibilityConstraint
emailstringYesValid address, maximum 254 characters; normalized to lowercase. Legacy Email is accepted as an input alias.
optInbooleanYesMust be the literal value true. Missing, false, and non-Boolean values are excluded.
firstNamestringNoTrimmed; maximum 128 characters; control characters rejected.
lastNamestringNoTrimmed; maximum 128 characters; control characters rejected.
localestringNoTrimmed; maximum 35 characters; control characters rejected.
timeZonestringNoTrimmed; maximum 64 characters; control characters rejected.

Unknown fields are not emitted. This prevents unrelated profile data, tokens, internal notes, or provider configuration from flowing into a delivery module by accident.

Outputs

OutputTypeConditionDescription
statusstringAlwayssuccess or error.
recipientsarraySuccessEligible unique recipients with allowlisted fields only.
recipientCountintegerSuccessNumber of recipients selected.
excludedCountintegerSuccessNumber excluded because consent was absent/false or the normalized address was a duplicate.
errorobjectFailureSafe code, message, and retryable: false; it contains no recipient values.

The output is classified as confidential because email addresses and names are personal data. The module logs aggregate counts and validation codes only.

IntegrationAccount Requirements

No IntegrationAccount is required or read. EmailRecipientsModule performs no provider authentication, network request, delivery, suppression lookup, or mailbox operation.

The downstream sender is responsible for using its own READY IntegrationAccount and for enforcing provider scopes, verified senders, account quotas, and delivery-specific approvals.

Configuration

ConfigurationTypeDefaultDescriptionConstraint
recipientsJSON array[]Reviewed static audience. A non-empty array takes precedence over runtime input.Same object contract as the runtime input.
maxRecipientsinteger500Maximum number of source entries accepted in one execution.1–1,000.

The bound applies before filtering and deduplication. A list with more entries than the reviewed maximum fails as a unit rather than returning a partial audience.

Operations

The module exposes one deterministic operation:

  1. Resolve static or runtime recipients.
  2. Require an array and enforce the configured entry bound.
  3. Exclude entries without explicit opt-in.
  4. Validate and normalize eligible email addresses and optional text fields.
  5. Remove non-allowlisted fields.
  6. Suppress duplicate lowercase addresses while preserving first-seen order.
  7. Return the eligible list and aggregate counts.

The module does not infer consent from presence in a list, a published status, an account role, or a prior delivery. It also does not synthesize opt-in for legacy records.

Errors and Failure Modes

CodeCauseRetryableRecovery
RECIPIENTS_REQUIREDNo static or runtime recipient exists.NoSupply a non-empty recipient array.
INVALID_RECIPIENTSThe top-level value is not an array or cannot be normalized safely.NoCorrect the JSON shape.
INVALID_RECIPIENTAn eligible entry is not an object, has an invalid address, or contains an invalid supported text field.NoCorrect the indexed entry; the error omits its values.
INVALID_LIMITmaxRecipients is outside 1–1,000.NoChoose a supported bound.
LIMIT_EXCEEDEDThe source array is larger than maxRecipients.NoReduce or explicitly partition the reviewed audience.
NO_ELIGIBLE_RECIPIENTSEvery entry is opted out, lacks explicit opt-in, or is removed as a duplicate.NoReconcile consent records; do not override them in this module.

Validation failures produce only status and error. A prior successful output is cleared before every execution, so stale recipients cannot survive a later failure.

Example

Configured input:

{
"recipients": [
{
"email": "Ada@Example.com",
"firstName": "Ada",
"locale": "en-US",
"optIn": true
},
{
"email": "grace@example.com",
"firstName": "Grace",
"optIn": false
},
{
"email": "ada@example.com",
"optIn": true
}
],
"maxRecipients": 100
}

Expected result:

{
"status": "success",
"recipients": [
{
"email": "ada@example.com",
"firstName": "Ada",
"locale": "en-US",
"optIn": true
}
],
"recipientCount": 1,
"excludedCount": 2
}

This result means one address is eligible for the next workflow step. It does not mean a message was sent, accepted, delivered, opened, or compliant with campaign-specific policy.

Notes

  • Pagination: the module does not page an external audience. Partition large source datasets upstream under a reviewed workflow policy.
  • Limits: one execution accepts at most 1,000 source entries and defaults to 500. Provider-specific recipient and message limits still apply later.
  • Idempotency: selection is deterministic and side-effect free for the same configuration and input order.
  • API constraints: there is no external API call, credential, retry, redirect, or rate-limit behavior.
  • Destructive behavior: none. The module does not mutate a subscriber record, revoke consent, or send a message.
  • Consent boundary: optIn: true is necessary for selection but may not be sufficient for a particular jurisdiction, purpose, brand, or campaign. Apply current legal and organizational policies before delivery.
  • Suppressions: unsubscribe, bounce, complaint, frequency-cap, and provider suppression lists must be enforced by an authorized upstream or delivery-stage service.
  • Observability: logs contain counts and safe error codes only; recipient addresses and profile fields are not logged.
  • IntegrationAccount: none. Live provider verification is not applicable to this local module.