ProvenPin Install

Nodemailer email sending tested with jsonTransport: working versions (tested 2026-10-15)

Send multipart (HTML + text) emails with attachments through Nodemailer, swapping SMTP for jsonTransport in tests so nothing leaves the machine.

passed2 passed · 0 failed2026-10-15 11:55 UTC
Status
passed
Last passed
2026-10-15 11:55 UTC
Tests
2 / 2
Language
TypeScript
Runtime
node v22.23.3
pinned versions4
nodemailer@10.1.1tsx@4.23.15@types/node@24.19.2@types/nodemailer@8.0.2
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38730348195

The code

Exactly the files that passed. Your agent can pull them with get_recipe("nodemailer-templates-test-transport") (install), or see them on GitHub.

package.json
{
  "name": "nodemailer-templates-test-transport",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "nodemailer": "10.1.1"
  },
  "devDependencies": {
    "tsx": "4.23.15",
    "@types/node": "24.19.2",
    "@types/nodemailer": "8.0.2"
  }
}
src/mailer.ts
import nodemailer, { type Transporter } from "nodemailer";

// prod: nodemailer.createTransport({ host, port: 587, secure: false, auth: { user, pass } })
export const testTransport = () => nodemailer.createTransport({ jsonTransport: true });

export async function sendInvoice(t: Transporter, to: string, invoiceNo: string, pdf: Buffer) {
  const info = await t.sendMail({
    from: '"Billing" <billing@example.com>',
    to,
    subject: `Invoice ${invoiceNo}`,
    text: `Your invoice ${invoiceNo} is attached.`,
    html: `<p>Your invoice <b>${invoiceNo}</b> is attached.</p>`,
    attachments: [{ filename: `${invoiceNo}.pdf`, content: pdf, contentType: "application/pdf" }],
    headers: { "X-Invoice": invoiceNo },
  });
  return info;
}
test/mailer.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { sendInvoice, testTransport } from "../src/mailer.ts";

test("builds a multipart message with attachment", async () => {
  const info: any = await sendInvoice(testTransport(), "ada@example.com", "INV-7", Buffer.from("%PDF-1.4"));
  const msg = JSON.parse(info.message);
  assert.equal(msg.subject, "Invoice INV-7");
  assert.deepEqual(msg.to.map((a: any) => a.address), ["ada@example.com"]);
  assert.match(msg.html, /<b>INV-7<\/b>/);
  assert.ok(msg.text);
  assert.equal(msg.attachments[0].filename, "INV-7.pdf");
  assert.equal(Buffer.from(msg.attachments[0].content, "base64").toString(), "%PDF-1.4");
  const headers = Object.fromEntries(Object.entries(msg.headers ?? {}).map(([k, v]) => [k.toLowerCase(), v]));
  assert.equal(headers["x-invoice"], "INV-7");
});

test("envelope has the right sender and recipients", async () => {
  const info: any = await sendInvoice(testTransport(), "bo@example.com", "INV-8", Buffer.alloc(1));
  assert.deepEqual(info.envelope, { from: "billing@example.com", to: ["bo@example.com"] });
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.