SendDart in .NET Applications: Scope Workers and Preserve Cancellation Evidence
Build a .NET email integration with deliberate dependency lifetimes, hosted-worker scope, structured exceptions and durable recovery.
TL;DR
- Record durable intent at the HTTP endpoint; let a worker claim the notification, resolve dependencies, call the provider and store evidence so the application's obligation persists beyond the original request.
- Align dependency lifetimes by passing a notification identifier into a worker scope, loading the record and tenant context there to avoid using disposed request-scoped services or carrying private data in queue arguments.
- Treat cancellation as local interruption, not proof of delivery; preserve operation keys and evidence, reconcile uncertain outcomes before resubmitting, and test host shutdown and duplicate-job scenarios to verify recovery.
Hosted work needs an ownership model
An ASP.NET Core application can run background work through hosted services, but that mechanism alone does not define persistence, message uniqueness or provider recovery. Decide where notification intent lives and how another process can recover it after a restart.
A useful design gives the HTTP endpoint responsibility for authorization and durable intent. A worker claims the notification, resolves its dependencies, calls the provider and stores evidence. The application's database retains the obligation even when the web request and its scoped services have ended.
Microsoft's hosted-service documentation explains background service lifecycle and scoped-service considerations. Use those facilities within a durable design rather than assuming that any task started by the host is guaranteed to finish. ASP.NET Core hosted services.
Align dependency lifetimes with execution
A request-scoped database context should not be captured and used later by a long-running background operation after the request has ended. The worker needs an appropriate scope for each unit of work under the application's dependency-injection design.
Pass a notification identifier instead of a live request object or service instance. Load the record and its authorized tenant context inside the worker scope. This avoids accidental dependence on disposed resources and reduces the amount of private data carried in queue arguments.
Review the provider client's documented lifecycle and HTTP configuration. Reuse or construct it according to supported behavior rather than inventing an extension method or registration API that the package does not provide.
Use the actual SDK response and exception model
SendDart's .NET SDK exposes asynchronous operations and throws SendDartException for documented non-success API responses. Structured fields describe the status, machine-readable name and additional evidence. Keep that information available to the worker's recovery decision. SendDart .NET SDK.
Do not match exception messages as stable protocol values. Human-readable text can change and may be sanitized. Translate structured failures into application outcomes such as rejected, delayed or uncertain, while retaining a restricted diagnostic record.
Keep the API credential in trusted server configuration. A controller response, client configuration object or exception page must not expose it. Test error paths with fake credential-shaped values to verify that logging and diagnostics redact them.
Related reading: Best Email API: Choose With a Production Acceptance Test.
Store intent before scheduling execution
Record the business event and notification intent together where the data model allows it. An email confirmation should not describe a transaction that later rolls back. A separate queue publication after commit also needs recovery if the process stops between those steps.
A durable outbox or equivalent record lets a dispatcher discover work independently of the original request. A hosted service can process it, or a separate worker can do so. The important property is retained intent and concurrency-safe claiming, not the name of the hosting abstraction.
Enforce uniqueness for business event and message purpose. A duplicate upstream callback should find the existing notification rather than create a second operation key. Different legitimate messages associated with the same order must remain distinct.
Related reading: Scheduled Email Delivery: Store the Time, Content and Cancellation State.
Interpret cancellation carefully
A cancellation token can stop local waiting or signal shutdown, but it does not establish whether the provider accepted an already-submitted request. Preserve the operation key and any original message identifier when a call is interrupted.
Use the SDK's documented options and methods rather than assuming every operation accepts the same token or idempotency parameter. Budget the call so the worker has time to persist evidence before its shutdown or execution deadline.
A retry of a supported operation should retain the original identity and immutable payload. Do not generate a new key merely because a hosted-service iteration restarted. If the outcome is uncertain, reconcile before submitting a replacement message or switching providers.
Keep content versions and policy checks separate
A notification should render from a fixed template version or saved content snapshot. This makes retries reproducible across deployments. If the business needs a corrected message, create a new authorized notification instead of mutating the old payload invisibly.
Current sending policy still needs a fresh check near execution. A tenant may be disabled or a recipient suppressed while the job waits. Record a deliberate skipped outcome when policy blocks the send so it does not enter an inappropriate retry path.
Attachments should reference protected, versioned resources. Avoid placing large private files or unrestricted URLs into broadly accessible queue metadata. The worker should resolve only resources the notification is authorized to send.
Ingest provider events durably
The callback endpoint should verify the raw request under the provider's signature contract, validate the event and store a unique observation. Slow downstream processing can occur after that durable receipt.
Correlate through the stored provider message identity and tenant ownership. A callback that arrives before the send result is committed needs a controlled reconciliation path. Duplicate delivery must not create duplicate alerts or repeated business actions.
Keep a timeline rather than overwriting evidence blindly. An older acceptance observation should not erase a later failure, and a delivery event should not be labeled proof of inbox placement or reading.
Test lifetimes as part of release
Exercise a request ending before worker execution, a scoped dependency recreated correctly, a host shutdown during submission and a duplicate job. Assert the number of external operations and the retained notification state.
Run controlled SDK simulations for error classification and a separate integration canary for real credentials and sender setup. No single successful asynchronous call proves the complete workflow.
A maintainable .NET integration respects service lifetimes and remote uncertainty together. The host runs the worker, but durable intent and structured evidence make the system recoverable after that host stops.