@logickernel/cartero
v0.2.0
Published
Email notification library with markdown templates
Maintainers
Readme
@logickernel/cartero
Email notification library with markdown templates. Define templates as markdown files with Handlebars variables, and cartero handles rendering, image embedding, and SMTP delivery.
Installation
npm install @logickernel/carteroFor GCS image support (optional):
npm install @google-cloud/storageQuick Start
import { send } from '@logickernel/cartero';
send('invitation', '[email protected]', {
sender_name: 'Alice',
organization_name: 'Acme',
});Configuration
Environment variables (defaults tuned for Gmail SMTP):
| Variable | Default | Required | Description |
|---|---|---|---|
| CARTERO_SMTP_HOST | smtp.gmail.com | No | SMTP server |
| CARTERO_SMTP_PORT | 587 | No | SMTP port |
| CARTERO_SMTP_SECURE | false | No | Use TLS |
| CARTERO_SMTP_USER | — | Yes | SMTP username |
| CARTERO_SMTP_PASSWORD | — | Yes | SMTP password / app password |
| CARTERO_FROM_EMAIL | CARTERO_SMTP_USER | No | Sender email address |
| CARTERO_TEMPLATES_DIR | ./templates | No | Path to templates directory |
Gmail App Password
Gmail and Google Workspace require an App Password rather than your account password:
- Enable 2-Step Verification on your Google account.
- Go to Security > App passwords and generate a password for "Mail".
- Use that 16-character password (no spaces) as
CARTERO_SMTP_PASSWORD.
Templates
Each template is a directory containing a template.md file:
templates/
invitation/
template.md
images/
logo.pngtemplate.md
---
subject: "You've been invited to {{organization_name}}"
---

**{{sender_name}}** invited you to **{{organization_name}}**.
[Accept]({{invitation_url}})- Directory name = template ID
subjectin frontmatter is required, supports{{variables}}- Body is markdown with
{{variables}} - Images: local paths, HTTP/HTTPS URLs, or
gs://GCS URIs - Images are embedded as CID attachments (displayed inline)
API
send(templateId, to, data)
function send(templateId: string, to: string, data: Record<string, string>): Promise<void>Returns a promise that resolves when the email is sent. Errors are caught and logged, never thrown. Callers should await in serverless environments (Cloud Run, Lambda) to ensure the email is delivered before the process exits.
Next.js Integration
Cartero depends on nodemailer, which uses Node.js built-in modules (net, tls, dns, stream) that webpack cannot bundle. In a Next.js project, add cartero to serverExternalPackages in next.config.ts:
const nextConfig: NextConfig = {
serverExternalPackages: ["@logickernel/cartero"],
};Without this, Next.js will attempt to webpack-bundle nodemailer's Node.js internals into the server bundle, causing runtime errors. This applies to any framework that uses webpack or similar bundlers for server-side code.
Development
npm test # unit tests
npm run test:integration # end-to-end with real SMTP + IMAP
npm run build # compile to dist/
npm run typecheck # type checking without emitPublishing
The package is published to npm under the @logickernel scope. The npm account requires 2FA, so publishing will prompt for browser-based authentication.
npm publish --access publicTo avoid the OTP prompt in CI, create a Granular Access Token from the npm website (Account > Access Tokens) with publish permissions for the @logickernel scope, then configure it as NPM_TOKEN.
