Skip to content

Mail

Email sending via Postmark or SMTP with a template system.

Setup

MailService is automatically registered by createApp(). Configure via environment variables:

bash
# Provider selection
MAIL_PROVIDER=smtp   # or 'postmark'
MAIL_FROM=noreply@example.com
MAIL_FROM_NAME="My App"

# SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD_SECRET=secret
SMTP_TLS=true

# Postmark
POSTMARK_SECRET=your-api-token

Sending Emails

Direct Send

typescript
import { MailService } from '@zyno-io/dk-server-foundation';

class OrderService {
    constructor(private mail: MailService) {}

    async sendConfirmation(order: Order) {
        await this.mail.send({
            to: { address: order.email, name: order.name },
            subject: 'Order Confirmation',
            message: `<h1>Your order #${order.id} has been placed.</h1>`,
            plainMessage: `Your order #${order.id} has been placed.`
        });
    }
}

Template Send

typescript
await this.mail.sendFromTemplate({
    to: { address: 'user@example.com' },
    template: WelcomeEmail,
    data: { name: 'Alice' }
});

Prepared Messages

Prepare a message without sending (useful for previews or queuing):

typescript
const prepared = await this.mail.prepare({
    to: { address: 'user@example.com' },
    subject: 'Hello',
    message: '<h1>Hello</h1>'
});

const preparedFromTemplate = await this.mail.prepareFromTemplate({
    to: { address: 'user@example.com' },
    template: WelcomeEmail,
    data: { name: 'Alice' }
});

Templates

Create email templates by extending MailTemplate:

typescript
import { MailTemplate } from '@zyno-io/dk-server-foundation';

class WelcomeEmail extends MailTemplate<{ name: string; loginUrl: string }> {
    subject = 'Welcome to Our App!';

    generateHtml() {
        return `
            <h1>Welcome, ${this.data.name}!</h1>
            <p>Get started by <a href="${this.data.loginUrl}">logging in</a>.</p>
        `;
    }

    generateText() {
        return `Welcome, ${this.data.name}! Log in at: ${this.data.loginUrl}`;
    }
}

MailTemplate<T>

Property / MethodTypeDescription
subjectstringEmail subject line (abstract)
dataTTemplate data (set by the framework)
generateHtml()stringHTML body (abstract)
generateText()string | voidPlain text body (optional)

Message Properties

MessageProperties

PropertyTypeRequiredDescription
to{ address: string; name?: string }YesRecipient
from{ address: string; name?: string }NoSender (defaults to MAIL_FROM)
replyTo{ address: string; name?: string }NoReply-to address
subjectstringYesSubject line
messagestringYesHTML body
plainMessagestringNoPlain text body
attachments{ name, content, contentType, cid? }[]NoFile attachments

TemplateMessageProperties<T>

PropertyTypeRequiredDescription
to{ address: string; name?: string }YesRecipient
templateClassType<MailTemplate<T>>YesTemplate class
dataTYesTemplate data

Providers

SMTP

Uses nodemailer. Configured via SMTP_* environment variables.

Postmark

Uses the Postmark API. Configured via POSTMARK_SECRET.

Both providers implement the MailProvider interface:

typescript
interface MailProvider {
    send(message: PreparedMessageProperties): Promise<string>;
}

The return value is a provider-specific message ID.

Configuration

VariableTypeDefaultDescription
MAIL_PROVIDERstringsmtpProvider: smtp or postmark
MAIL_FROMstringDefault sender address
MAIL_FROM_NAMEstringDefault sender name
SMTP_HOSTstring127.0.0.1SMTP host
SMTP_PORTnumber1025SMTP port
SMTP_USERstringSMTP username
SMTP_PASSWORD_SECRETstringSMTP password
SMTP_TLSbooleanfalseEnable TLS
POSTMARK_SECRETstringPostmark API token

Released under the MIT License.