60 lines
2.6 KiB
Markdown
60 lines
2.6 KiB
Markdown
# `email-channel` — Email delivery channel
|
|
|
|
## Purpose
|
|
|
|
`email-channel.ts` ships the `EmailChannel` `DeliveryChannel` implementation. The class is provider-neutral: the integration seam is a caller-supplied `sendFn(message)` callback that performs the actual SMTP / API call. Wiring a real provider (Amazon SES, SendGrid, Postmark, Mailgun, or an internal MTA) is a matter of supplying a function with the documented signature. The channel swallows transport errors and returns them as `DeliveryResult { success: false, error }`, never propagating exceptions to the router.
|
|
|
|
## Features
|
|
|
|
- Provider-neutral via injectable `sendFn`.
|
|
- `canSend` accepts `email` channel + `@`-bearing recipient — keeps malformed addresses from reaching upstream providers.
|
|
- Falls back to `"(No subject)"` when the notification carries no subject.
|
|
- Propagates `metadata` to the provider message — useful for tracking IDs.
|
|
- Injectable `Clock` for deterministic `timestamp` fields in tests.
|
|
|
|
## Usage: Basic
|
|
|
|
```ts
|
|
import { EmailChannel } from "@suaveplan/notification-channel";
|
|
|
|
const channel = new EmailChannel({
|
|
from: "noreply@example.com",
|
|
sendFn: async (msg) => ({ messageId: await sesClient.send(msg) }),
|
|
});
|
|
|
|
const result = await channel.send(notification);
|
|
if (!result.success) reportError(result.error);
|
|
```
|
|
|
|
## Usage: Advanced
|
|
|
|
```ts
|
|
import { EmailChannel } from "@suaveplan/notification-channel";
|
|
|
|
const channel = new EmailChannel({
|
|
from: "alerts@example.com",
|
|
sendFn: async (msg) => {
|
|
const messageId = await sendgrid.send({
|
|
to: msg.to,
|
|
from: "alerts@example.com",
|
|
subject: msg.subject,
|
|
content: [{ type: "text/plain", value: msg.body }],
|
|
customArgs: msg.metadata as Record<string, string> | undefined,
|
|
});
|
|
return { messageId };
|
|
},
|
|
clock: () => testNow,
|
|
});
|
|
```
|
|
|
|
## API Reference
|
|
|
|
- `EmailChannel(config: EmailChannelConfig)` — constructor.
|
|
- `EmailChannelConfig` — `{ from, sendFn, clock? }`.
|
|
- `EmailMessage` — `{ to, subject, body, metadata? }` passed to `sendFn`.
|
|
- `canSend(n): boolean`, `send(n): Promise<DeliveryResult>` — `DeliveryChannel` impl.
|
|
|
|
## Implementation Notes
|
|
|
|
The default subject `"(No subject)"` matches the upstream `@suaveplan/notification-channel@1.2.6` behaviour so consumer dashboards keep showing a non-empty subject column. Non-`Error` throws inside `sendFn` are coerced via `String(err)` so the `DeliveryResult.error` is always a string. The injected `clock` only affects the `timestamp` field — the upstream provider's own timestamps remain authoritative for SLA tracking.
|