JSPM

  • Created
  • Published
  • Downloads 23248
  • Score
    100M100P100Q183882F
  • License MIT

Send mail via Node.js with ZeptoMail

Package Exports

  • zeptomail
  • zeptomail/package.json

Readme

ZeptoMail Node.js SDK

Send transactional email and manage your ZeptoMail account — agents, domains, suppression lists, and email logs from Node.js.

Table of Contents


Installation

Sign up at ZeptoMail if you haven't already, then install the package:

npm install zeptomail

Requirements

  • Node.js ≥ 20
  • Full TypeScript support is included — no separate @types/ package needed.

Note: Email sending uses a Send Mail Token for authentication and the management clients (Agents, Domains, Suppression, Email Logs) use OAuth 2.0 via AuthenticationClient.

Email Sending

Obtain your Send Mail Token from the ZeptoMail dashboard.

import { SendMailClient } from "zeptomail";
// CommonJS: const { SendMailClient } = require("zeptomail");

const client = new SendMailClient({
    url: "api.zeptomail.com/", // required
    token: "<Send mail token>", // required
});

Send mail

await client.sendMail({
    from: { address: "sender@example.com", name: "Sender" },
    to: [
        { email_address: { address: "to@example.com", name: "Recipient" } }
    ],
    reply_to: [{ address: "reply@example.com", name: "Reply" }],
    cc: [{ email_address: { address: "cc@example.com", name: "CC" } }],
    bcc: [{ email_address: { address: "bcc@example.com", name: "BCC" } }],
    subject: "Sending with ZeptoMail",
    htmlbody: "<strong>Easy to do from anywhere, with Node.js</strong>",
    textbody: "Easy to do from anywhere, with Node.js",
    track_clicks: true,
    track_opens: true,
    client_reference: "<client reference>",
    mime_headers: { "X-Zylker-User": "test-xxxx" },
    attachments: [
        { content: "<base64>", mime_type: "image/jpg", name: "report.jpg" },
        { file_cache_key: "<File Cache Key>", name: "cached-file" }
    ],
    inline_images: [
        { content: "<base64>", mime_type: "image/jpg", cid: "img-header" },
        { file_cache_key: "<File Cache Key>", cid: "img-footer" }
    ]
});

Send batch mail

Batch mail lets you send one request for up to 500 recipients, with per-recipient personalisation via merge_info. Use {{placeholder}} syntax in subject, htmlbody, textbody, or client_reference. The matching keys from each recipient's merge_info are substituted before delivery.

Two merge_info placement modes:

  • Per-recipient only — set merge_info inside each to entry. Each recipient gets their own values.
  • Per-recipient + global fallback — set merge_info both inside to entries and at the top level. Recipients with their own merge_info use it; recipients without one fall back to the top-level values.
await client.sendBatchMail({
    from: { address: "sender@example.com", name: "Sender" },
    to: [
        {
            email_address: { address: "alice@example.com", name: "Alice" },
            merge_info: { name: "Alice", company: "Acme" }  // per-recipient values
        },
        {
            email_address: { address: "bob@example.com", name: "Bob" },
            merge_info: { name: "Bob", company: "Globex" }
        },
        {
            email_address: { address: "carol@example.com", name: "Carol" }
            // no merge_info — falls back to top-level merge_info below
        }
    ],
    // Top-level merge_info: used as fallback for recipients without their own
    merge_info: { name: "Customer", company: "Your Company" },
    reply_to: [{ address: "reply@example.com", name: "Reply" }],
    subject: "Hi {{name}}, a message from {{company}}",
    htmlbody: "<p>Hi {{name}}, welcome to {{company}}.</p>",
    textbody: "Hi {{name}}, welcome to {{company}}.",
    track_clicks: true,
    track_opens: true,
    client_reference: "ref-{{name}}",
});

Limit: A single batch request supports up to 500 recipients. To request a higher limit, contact support@zeptomail.com.

Send template mail

Uses a pre-built template from your ZeptoMail dashboard. Provide either template_key or template_alias (or both).

await client.sendMailWithTemplate({
    template_key: "<template key>",
    template_alias: "<template alias>",
    from: { address: "sender@example.com", name: "Sender" },
    to: [{ email_address: { address: "to@example.com", name: "Recipient" } }],
    cc: [{ email_address: { address: "cc@example.com", name: "CC" } }],
    bcc: [{ email_address: { address: "bcc@example.com", name: "BCC" } }],
    reply_to: [{ address: "reply@example.com", name: "Reply" }],
    merge_info: { contact_number: "8787xxxxxx789", company: "example.com" },
    client_reference: "<client reference>",
    mime_headers: { "X-Test": "test" }
});

Send batch template mail

Combines a pre-built template with per-recipient merge_info for up to 500 recipients per request. The same two merge_info placement modes available in sendBatchMail apply here; per-recipient values inside to, with an optional top-level fallback for recipients that don't have their own.

await client.mailBatchWithTemplate({
    template_key: "<template key>",
    template_alias: "<template alias>",
    from: { address: "sender@example.com", name: "Sender" },
    to: [
        {
            email_address: { address: "alice@example.com", name: "Alice" },
            merge_info: { contact: "9600000023", company: "Acme" } // per-recipient
        },
        {
            email_address: { address: "bob@example.com", name: "Bob" },
            // no merge_info — falls back to top-level merge_info below
        }
    ],
    // Top-level merge_info: fallback for recipients without their own
    merge_info: { contact: "0000000000", company: "Default Co." },
    reply_to: [{ address: "reply@example.com", name: "Reply" }],
    client_reference: "<client reference>",
    mime_headers: { "X-Test": "test" }
});

Limit: A single batch request supports up to 500 recipients. To request a higher limit, contact support@zeptomail.com.



The clients for managing Agents, Domains, Suppression lists, and Email Logs use OAuth 2.0 rather than a send-mail token. Before using any of these clients, set up an AuthenticationClient with the appropriate scope.

Authentication — one client per scope

Each REST client requires its own AuthenticationClient instance. ZeptoMail issues scope-based refresh tokens — a token that authorises agent operations will not work for domain or suppression operations.

Client Specific scopes All-access scope
AgentClient Zeptomail.MailAgents.READ
Zeptomail.MailAgents.CREATE
Zeptomail.MailAgents.UPDATE
Zeptomail.MailAgents.DELETE
Zeptomail.MailAgents.All
DomainClient Zeptomail.Domains.READ
Zeptomail.Domains.CREATE
Zeptomail.Domains.UPDATE
Zeptomail.Domains.DELETE
Zeptomail.Domains.All
SuppressionClient Zeptomail.Suppressions.READ
Zeptomail.Suppressions.CREATE
Zeptomail.Suppressions.UPDATE
Zeptomail.Suppressions.DELETE
Zeptomail.Suppressions.All
EmailLogsClient Zeptomail.email.READ

Use *.All to cover every operation under that client with a single token. Use specific scopes (e.g. Zeptomail.Domains.READ) to grant only the minimum privilege needed.

import { AuthenticationClient } from "zeptomail";

// One AuthenticationClient per scope — do NOT share across different clients
const agentAuth = new AuthenticationClient({
    clientId: "<your-client-id>",
    clientSecret: "<your-client-secret>",
    refreshToken: "<agent-scoped-refresh-token>",
    dataCenter: "US", // "US" | "EU" | "IN" | "AU" | "JP" | "CN"
    // Optional:
    timeout: 30_000,  // token-refresh HTTP timeout in ms (default: 30 000)
    bufferMs: 300_000, // refresh token this many ms before expiry (default: 5 min)
    apiVersion: "v1.1", // API version (default: "v1.1")
});

// Separate instances per scope:
const domainAuth     = new AuthenticationClient({ ... });
const suppressionAuth = new AuthenticationClient({ ... });
const emailLogsAuth  = new AuthenticationClient({ ... });

Each REST client accepts its AuthenticationClient via the constructor, or you can set it later:

const agents = new AgentClient({ authenticationClient: agentAuth });

// Or set after construction:
agents.setAuthenticationClient(agentAuth);

Rotating a refresh token

Call updateCredentials() on the existing instance — no need to create a new client:

agentAuth.updateCredentials({ refreshToken: "<new-refresh-token>" });
// The cached access token is automatically invalidated; the next request fetches a fresh one.

Pre-warming the token at startup

Call authenticate({ force: true }) to fetch a token before the first real request, avoiding latency on the first API call:

await agents.authenticate({ force: true });

Disabling auto-refresh

By default, tokens are refreshed automatically. To manage tokens manually:

const agents = new AgentClient({
    authenticationClient: agentAuth,
    autoAuthenticate: false, // you are responsible for calling refreshAccessToken()
});

await agentAuth.refreshAccessToken(); // call this before making requests

🧩 Agent Management

Manage mail agents (sending identities), their API keys, and SMTP passwords.

import { AgentClient } from "zeptomail";

const agents = new AgentClient({ authenticationClient: agentAuth });

List all agents

Required scope: Zeptomail.MailAgents.READ or Zeptomail.MailAgents.All

const { data } = await agents.getAllAgents();
// data: Agent[]

Add an agent

Required scope: Zeptomail.MailAgents.CREATE or Zeptomail.MailAgents.All

const { data } = await agents.addAgent({
    agentName: "My Agent",
    description: "Production sending agent",
});
// data: Agent

Update an agent

Required scope: Zeptomail.MailAgents.UPDATE or Zeptomail.MailAgents.All

const { data } = await agents.updateAgent({
    agentKey: "<mailagent-key>",
    agentName: "Updated Name",
    description: "Updated description",
});

Delete an agent

Required scope: Zeptomail.MailAgents.DELETE or Zeptomail.MailAgents.All

await agents.deleteAgent({ agentKey: "<mailagent-key>" });

API Keys

// List API keys
// scope: Zeptomail.MailAgents.READ or .All
const { data } = await agents.getAPIKeys({ agentKey: "<mailagent-key>" });

// Generate a new API key
// scope: Zeptomail.MailAgents.CREATE or .All
const { data } = await agents.generateAPIKey({ agentKey: "<mailagent-key>" });
// data.password contains the plaintext key — store it securely

// Revoke an API key
// scope: Zeptomail.MailAgents.DELETE or .All
await agents.revokeAPIKey({ agentKey: "<mailagent-key>", id: "<api-key-id>" });

SMTP Passwords

// List SMTP passwords
// scope: Zeptomail.MailAgents.READ or .All
const { data } = await agents.getSMTPList({ agentKey: "<mailagent-key>" });

// Generate a new SMTP password
// scope: Zeptomail.MailAgents.CREATE or .All
const { data } = await agents.generateSMTPPassword({ agentKey: "<mailagent-key>" });
// data.password contains the plaintext password — store it securely, it won't be shown again

// Delete an SMTP password
// scope: Zeptomail.MailAgents.DELETE or .All
await agents.deleteSMTPPassword({
    agentKey: "<mailagent-key>",
    passwordId: "<password-id>",
});

🌐 Domain Management

Manage sending domains — add, verify, update, and delete.

import { DomainClient } from "zeptomail";

const domains = new DomainClient({ authenticationClient: domainAuth });

List all domains

Required scope: Zeptomail.Domains.READ or Zeptomail.Domains.All

const { data } = await domains.getAllDomains();
// data: DomainSummary[]

Get domain details

Required scope: Zeptomail.Domains.READ or Zeptomail.Domains.All

const { data } = await domains.getDomainDetails({ domainKey: "<domain-key>" });
// data: DomainDetail[]  (includes DKIM and CNAME records)

Add a domain

Required scope: Zeptomail.Domains.CREATE or Zeptomail.Domains.All

const { data } = await domains.addDomain({
    domainName: "mail.example.com",
    bounceDomainPrefix: "bounce", // forms bounce.mail.example.com
    agentKeys: ["<mailagent-key>"], // optional
});
// data.dkim and data.cname contain the DNS records to configure

Update a domain

Required scope: Zeptomail.Domains.UPDATE or Zeptomail.Domains.All

const { data } = await domains.updateDomain({
    domainKey: "<domain-key>",
    newDomainName: "mail2.example.com",          // optional
    newBounceDomainPrefix: "bounce2",             // optional
    associateAgents: ["<mailagent-key>"],         // optional
    disassociateAgents: ["<other-mailagent-key>"], // optional
});

Verify a domain

Required scope: Zeptomail.Domains.UPDATE or Zeptomail.Domains.All

Triggers DNS verification. Configure the DKIM and CNAME records returned from addDomain / getDomainDetails in your DNS provider first.

const { data } = await domains.verifyDomain({ domainKey: "<domain-key>" });
// data.status will be "verified" if DNS records are correct

Delete a domain

Required scope: Zeptomail.Domains.DELETE or Zeptomail.Domains.All

await domains.deleteDomain({ domainKey: "<domain-key>" });

🚫 Suppression Management

Manage the Do-Not-Disturb (DND) / suppression list for email addresses and domains.

import { SuppressionClient } from "zeptomail";

const suppression = new SuppressionClient({ authenticationClient: suppressionAuth });

List suppression entries

Required scope: Zeptomail.Suppressions.READ or Zeptomail.Suppressions.All

const response = await suppression.getSuppressionList({
    dndType: "email", // "email" | "domain"
    // All filters below are optional:
    dateFrom: new Date("2024-01-01"),
    dateTo: "2024-12-31",
    offset: 0,
    limit: 50,
    agentKey: "<mailagent-key>",
    searchValue: "user@example.com",
});

Add suppression entries

Required scope: Zeptomail.Suppressions.CREATE or Zeptomail.Suppressions.All

await suppression.addSuppressionEntry({
    dndType: "email",
    values: ["blocked@example.com", "spam@test.com"],
    action: "reject",                      // "reject" | "suppress" | "suppress_tracking"
    agentKeys: ["<mailagent-key>"],        // optional — applies to all agents if omitted
    description: "Bounced addresses",      // optional
});

Note: "suppress_tracking" is only valid when dndType is "email".

Update suppression entries

Required scope: Zeptomail.Suppressions.UPDATE or Zeptomail.Suppressions.All

await suppression.updateSuppressionEntry({
    dndType: "email",
    values: ["blocked@example.com"],
    action: "suppress",
});

Delete suppression entries

Required scope: Zeptomail.Suppressions.DELETE or Zeptomail.Suppressions.All

await suppression.deleteSuppressionEntry({
    dndType: "domain",
    values: ["spam.com", "malicious.org"],
});

📋 Email Logs

Query sent email logs and retrieve full details for a specific email.

import { EmailLogsClient } from "zeptomail";

const logs = new EmailLogsClient({ authenticationClient: emailLogsAuth });

List email logs

Required scope: Zeptomail.email.READ

All parameters are optional.

const response = await logs.getAllEmailLogs({
    mailAgentKey: "<mailagent-key>",
    requestId: "<request-id>",
    dateFrom: new Date("2024-06-01"),
    dateTo: new Date("2024-06-30"),
    from: "sender@example.com",
    to: "recipient@example.com",
    cc: "cc@example.com",
    bcc: "bcc@example.com",
    recipient: "any@example.com", // matches to / cc / bcc
    subject: "Welcome",
    clientReference: "<client-ref>",
    offset: 0,
    limit: 100,
    isHardBounced: false,
    isSoftBounced: false,
    isMailFailure: false,
    isDelivered: true,
});

Get full details for a single email

Required scope: Zeptomail.email.READ

const response = await logs.getEmailDetails({
    emailReference: "<email-reference-id>",
});

⚠️ Error Handling

All clients throw typed errors. Import the classes you need and use instanceof to branch:

import { AuthenticationError, NetworkError, TimeoutError, ApiError, ValidationError } from "zeptomail";

try {
    const { data } = await agents.getAllAgents();
} catch (err) {
    if (err instanceof ValidationError) {
        // A required parameter was missing or invalid before the request was sent.
    } else if (err instanceof AuthenticationError) {
        // Token refresh failed — check clientId, clientSecret, refreshToken.
    } else if (err instanceof NetworkError) {
        // Could not reach the server — check connectivity.
    } else if (err instanceof TimeoutError) {
        // The token-refresh or API request timed out.
    } else if (err instanceof ApiError) {
        // The server returned an HTTP error response.
    }
}

📒 Contact Us

Contact us at support@zeptomail.com for any issue resolutions or assistance.