Extend Mursil at the seams below. A new product behavior is still a vertical slice, as Add a feature describes. These interfaces are the places the slice plugs in.

Calling Mursil

Mursil.Integration (AddMursilIntegration) is the supported host package. It registers:

  • ITransactionalEmailSender, ICommunicationQueue, and IEmailEngine, so a host that already speaks those abstractions can point them at Mursil
  • IMursilIntegrationClient for draft template push and status lookup
  • a Refit client for POST /api/v1/mursil/messages/email, POST /api/v1/mursil/templates/push, and GET /api/v1/mursil/messages/status

IMursilIntegrationTenantAccessor supplies a tenant id for one call. The package reads accessors first, then Mursil:Integration:DefaultTenantId. It omits the tenant on the wire when Mursil:MultiTenancy is false.

Mursil.Client is a smaller in-repo send client (Mursil:TransactionalEmail). It is not a published admin UI, and it is not a second portal.

Provider transport

IMursilProviderEmailTransport sends one already-rendered message. The request carries the ProviderKind, the settings secret reference, the from and to addresses, and the rendered bodies. Implementations live in Infrastructure and call the CleanArch Pro provider packages.

ProviderKind is the closed set the portal offers: SendGrid, Smtp, TestSink, AwsSes, AzureCommunicationServices, MicrosoftGraph, Postmark, and Mailgun. Adding a kind means a domain value, a transport branch, and tests. It does not mean a new settings screen that accepts a raw secret. Connections keep a secret reference.

Local SMTP settings are Email:Smtp (Host, Port, UserName, Password, EnableSsl). Compose points that section at Mailpit. SendGrid remains an optional kind.

CleanArch Pro publishes a Resend email module. That module is part of the framework and is not the documented send path yet. Mailpit over SMTP is the local path. SendGrid is the optional vendor path this product documents.

DNS and tracking

IMursilDnsTxtLookup is the DNS read used when a sender domain is verified. Replace it only when the host must resolve TXT records through a different network path. The verify route and the portal page stay the same.

Mursil:Tracking (PublicBaseUrl, HmacSecret) signs open, click, and preference tokens. The rewriter that inserts those URLs is MursilHtmlTrackingRewriter. When multi-tenancy is off, the public URL does not contain the deployment tenant id.

Persistence and dispatch

Delivery claim, retry, and dead-letter run in application handlers (DispatchDueDeliveries and the triage commands) against repositories. A new delivery rule belongs next to those handlers, not in a database routine and not in the endpoint.

Provider webhook secrets are resolved through IMursilProviderWebhookSecretResolver. The ingest route stays POST /api/v1/mursil/providers/{providerConnectionId}/events.

Portal

Operator UI is Mursil.Admin. New pages follow an existing page: a route, an [Authorize] policy, and IMursilOperationsClient. The client is a Refit interface aimed at Mursil.Server. There is no Mursil admin package and no separate UI package to extend.

The Developers page is a placeholder. Credential issuance is not an extension point yet. Hosts configure Mursil:Integration directly.

Framework boundary

Shared primitives (results, strongly typed ids, specifications, the mediator pipeline, theming) come from CleanArch Pro packages. If a seam is useful to more than Mursil, it belongs in that framework and Mursil takes the package. If it is product behavior, it stays in this repository as a slice.