Customizing Sending Logic
Relevant source files
The following files were used as context for generating this wiki page:
Customizing sending logic within Send Again involves configuring how emails are addressed, filtered, and formatted before being transmitted via Amazon SES. This system allows developers to define recipient audiences dynamically based on contact metadata or historical behavior, set rate limits to manage deliverability, and automate the inclusion of personalized footers and unsubscribe mechanisms.
The platform provides multiple interfaces for these customizations, including a REST API for programmatic control and a visual Campaign builder for defining complex multi-step workflows.
Recipient Targeting and Filtering
The system supports several modes for selecting recipients, ranging from manual entry to dynamic filtering based on contact "fields" or historical "events" (e.g., opens or clicks).
Recipient Modes
When initiating a send, users can choose between different selection strategies:
| Mode | Description |
|---|---|
manual | Recipients are provided as a static list of email addresses. |
all_contacts | Targets every contact currently stored in the workspace. |
verified_contacts | Targets contacts where the verified field is truthy. |
unverified_contacts | Targets contacts where the verified field is explicitly false. |
Sources: src/app/api/send/route.ts:25-29, src/lib/openapi.ts:89-94
Dynamic Rule Evaluation
For advanced targeting, the system uses a rule engine that evaluates RecipientCondition objects. These conditions are categorized into two types:
- Field Conditions: Match against arbitrary key-value metadata stored with a contact (e.g.,
companyis "Acme"). - History Conditions: Match based on whether a recipient has interacted with previous emails (e.g.,
eventTypeis "click" for a specificsubject).
Sources: src/app/app/page.tsx:210-230, src/app/campaigns/page.tsx:17-33
This diagram shows the logic used to filter contacts into a final recipient list based on workspace rules.
Sources: src/app/app/page.tsx:254-273
Automated Content Formatting
Before an email is enqueued, the system automatically processes the HTML body to include workspace-specific branding and compliance elements.
Footer and Unsubscribe Logic
Every email processed by appendWorkspaceFooter undergoes a transformation where placeholders are replaced with live data.
- Variables: Supports
{{unsubscribe_url}}and{{workspace_url}}. - Automatic Fallback: If a custom footer is provided but lacks an unsubscribe link, the system injects a default one to ensure compliance.
- Branding: A "sent with send-again.com" link is appended to the bottom of all messages.
Sources: src/lib/email-footer.ts:58-85
Variable Substitution
The sending logic supports basic templating using double curly braces (e.g., {{email}} or {{first_name}}). During the send job creation, these variables are mapped to the specific fields found in the Contact record.
Sources: src/app/app/page.tsx:1286-1293
Sending Constraints and Infrastructure
The sending logic is governed by environment configurations and workspace settings designed to protect sender reputation and manage costs.
Rate Limiting and Concurrency
To avoid SES throttling and improve deliverability, the system implements a configurable delay between individual sends.
- Rate Limit: Specified in milliseconds (ms) per workspace.
- Concurrency: Managed via
SEND_JOB_CONCURRENCY, determining how many parallel sends occur within a single batch. - Batch Size: Controlled by
SEND_JOB_BATCH_SIZE(defaulting to 50).
Sources: src/app/api/send/route.ts:318-322, README.md:145-147
Dry Run Mode
The API and UI both support a dryRun flag. When enabled, the system executes all resolution logic—including contact filtering and unsubscribe suppression—but returns the resulting count without enqueuing a job in the database or calling SES.
Sources: src/app/api/send/route.ts:251-257, src/lib/openapi.ts:409-411
Campaign Workflow Logic
The Campaign module extends basic sending logic into a state machine represented as a Directed Acyclic Graph (DAG).
Workflow Nodes
Workflows are composed of three primary node types that dictate the flow of a campaign:
- Send Node: Executes a send job to a specific audience.
- Delay Node: Pauses the workflow for a defined number of days and hours.
- Rule Node: Branches the workflow into
trueorfalsepaths based onRecipientConditionevaluation.
Sources: src/app/campaigns/page.tsx:43-69
Visual representation of a multi-step campaign workflow structure.
Sources: src/app/campaigns/page.tsx:476-523
Edge Constraints
Campaign transitions are strictly validated based on the source node type:
SendandDelaynodes only support a singlenextport.Rulenodes requiretrueandfalseports to handle branching logic.
Sources: src/app/campaigns/page.tsx:613-630
Summary
Customizing sending logic in Send Again centers on the orchestration of SendJobs. By combining dynamic recipient rules, automated footer injection, and granular rate limits, the system provides a flexible framework for both simple notifications and complex marketing automation. All logic is strictly bound to the Workspace ID, ensuring isolation of domains, contacts, and deliverability settings.