Files
skills/docs/communication/messaging/notification-channel/src/channels/email-channel.md
2026-05-29 08:20:56 +01:00

2.6 KiB

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

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

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.