@contract-kit/mail
v1.0.0
Published
Shared mail types for contract-kit mail providers
Maintainers
Readme
@contract-kit/mail
Shared mail port and test adapters for Contract Kit applications.
Application code should depend on MailerPort, not Resend, SMTP, or another
vendor SDK. Providers install a mailer port, while provider-specific clients
remain available as escape hatches.
Install
bun add @contract-kit/mailApp-facing port
import type { MailerPort } from "@contract-kit/mail";
export type AppPorts = {
mailer: MailerPort;
};
await ctx.ports.mailer.send({
to: "[email protected]",
subject: "Welcome",
html: "<h1>Hello</h1>",
});send requires at least one to recipient and accepts either text, html,
or both. Empty optional recipient lists are ignored, so callers can safely pass
filtered cc, bcc, or replyTo arrays.
await ctx.ports.mailer.send({
from: { email: "[email protected]", name: "Support" },
to: [
"[email protected]",
{ email: "[email protected]", name: "Admin" },
],
cc: "[email protected]",
replyTo: "[email protected]",
subject: "Account updated",
text: "Your account was updated.",
html: "<p>Your account was updated.</p>",
headers: {
"X-App-Event": "account.updated",
},
});Test adapter
Use the in-memory mailer in use case tests, job tests, and local examples:
import { createMemoryMailer } from "@contract-kit/mail";
const mailer = createMemoryMailer({
defaultFrom: "[email protected]",
});
await mailer.send({
to: "[email protected]",
subject: "Welcome",
text: "Hello",
});
expect(mailer.deliveries).toHaveLength(1);
expect(mailer.deliveries[0].message.to).toEqual(["[email protected]"]);Providers
@contract-kit/provider-mail-resendinstallsctx.ports.mailerbacked by Resend and exposesctx.ports.resend.clientas the escape hatch.@contract-kit/provider-mail-smtpinstallsctx.ports.mailerbacked by Nodemailer and exposesctx.ports.smtp.transporteras the escape hatch.
Implementing a provider
import type { MailerPort } from "@contract-kit/mail";
import { createProvider } from "@contract-kit/ports";
export const myMailProvider = createProvider({
name: "my-mail",
async setup() {
const client = createClient();
const mailer: MailerPort = {
async send(message) {
const result = await client.send(message);
return { id: result.id, provider: "my-mail" };
},
};
return {
ports: {
mailer,
myMail: { client },
},
};
},
});License
MIT
