Durable Workflows with Temporal
Relevant source files
The following files were used as context for generating this wiki page:
The Resend .NET SDK integrates with Temporal to execute email delivery as a durable, fault-tolerant background process. This system ensures that email delivery survives transient network interruptions, provider outages, or rate-limiting constraints by using built-in retry mechanisms and state management.
Sources: examples/README.md:28-44, examples/AsyncTemporal/README.md:1-5
Architecture and Components
The integration consists of three primary components: the Temporal Client, the Temporal Worker (hosting Workflows and Activities), and the Resend API client.
Component Overview
| Component | Class / Interface | Description |
|---|---|---|
| Workflow | EmailSendWorkflow | Orchestrates the delivery process and manages execution state. |
| Activity | EmailSendActivity | Performs the actual unit of work (calling the Resend API). |
| Worker | Temporalio.Extensions.Hosting | Hosts the workflow and activity implementations in a background service. |
| Client | ITemporalClient | Initiates workflow executions from the application code. |
Sources: examples/AsyncTemporal/Program.cs:20-33, examples/AsyncTemporal/Temporal/EmailSendWorkflow.cs:9-11
Data Flow and Execution
The following diagram illustrates the flow from the initial request to the final email delivery.
The EmailSendWorkflow uses a specific timeout configuration (ScheduleToCloseTimeout) of 5 minutes to manage activity execution.
Sources: examples/AsyncTemporal/Temporal/EmailSendWorkflow.cs:23-37, examples/AsyncTemporal/Program.cs:20-33
Implementation Details
Workflow Definition
The EmailSendWorkflow class defines the orchestration logic. It uses the [Workflow] attribute and identifies the entry point with [WorkflowRun]. It uses a dedicated workflow logger to avoid duplicate logs during state replay.
Sources: examples/AsyncTemporal/Temporal/EmailSendWorkflow.cs:9-25
Activity Definition
The activity implementation receives an EmailMessage and calls the IResend.EmailSendAsync method. To simulate or handle errors, the activity can be tested against a ResendMockClient which intentionally fails initial attempts to trigger Temporal's retry logic.
Sources: examples/AsyncTemporal/Temporal/EmailSendActivity.cs, examples/AsyncTemporal/README.md:38-48
Dependency Injection Setup
Configuration occurs in Program.cs by adding both the client and the hosted worker to the service collection.
// Temporal Client
builder.Services.AddTemporalClient(
clientTargetHost: "localhost:7233",
clientNamespace: "default" );
// Temporal Worker hosting Activity and Workflow
builder.Services.AddHostedTemporalWorker(
clientTargetHost: "localhost:7233",
clientNamespace: "default",
taskQueue: TemporalWorker.TaskQueue )
.AddScopedActivities<EmailSendActivity>()
.AddWorkflow<EmailSendWorkflow>();
Sources: examples/AsyncTemporal/Program.cs:20-33
Limitations and Constraints
Developers must account for payload size limits inherent to Temporal's gRPC-based communication.
| Constraint | Limit | Impact |
|---|---|---|
| Single Argument Size | 2 MB | Large email bodies or attachments may fail serialization. |
| Total gRPC Message | 4 MB | Includes all arguments and metadata for the activity call. |
Large Attachment Strategy
If an email exceeds the 2 MB limit, the EmailSendActivity should load content from a persistent store rather than receiving the full byte array in the activity argument. The Path property of the EmailAttachment can be utilized to store a reference for the activity to resolve prior to calling the Resend API.
Sources: examples/AsyncTemporal/README.md:55-72, src/Resend/IResend.cs:25-30
Summary
Durable workflows provide a reliable way to send emails by decoupling the application request from the API execution. By implementing EmailSendWorkflow and EmailSendActivity, the system gains automatic retries and persistence, ensuring that emails are eventually delivered even if the Resend API or network is temporarily unavailable.