Guides

Mailbox Setup

zend.sh is a BYOK (Bring Your Own Keys) platform. You connect your own mailboxes, and zend.sh handles rotation, health monitoring, and deliverability. This guide covers connecting the three supported provider types.

Google Workspace

Prerequisites

  • A Google Workspace account (not a free @gmail.com account)
  • 2-Step Verification enabled on the account

Generate an app password

  1. Go to Google Account Security
  2. Under "2-Step Verification", click App passwords
  3. Select "Mail" as the app and your device
  4. Copy the 16-character app password

Connect the mailbox

const account = await zend.accounts.create({
  email: 'outreach@yourcompany.com',
  provider: 'google',
  smtp_host: 'smtp.gmail.com',
  smtp_port: 465,
  smtp_username: 'outreach@yourcompany.com',
  smtp_password: 'xxxx xxxx xxxx xxxx', // app password
  imap_host: 'imap.gmail.com',
  imap_port: 993,
  imap_username: 'outreach@yourcompany.com',
  imap_password: 'xxxx xxxx xxxx xxxx', // same app password
})

Enable IMAP

IMAP must be enabled for reply detection:

  1. Open Gmail settings (gear icon)
  2. Go to Forwarding and POP/IMAP
  3. Under IMAP Access, select Enable IMAP
  4. Save changes

Microsoft 365

Microsoft 365 uses OAuth2 for authentication. You need to register an Azure AD application.

Register an Azure AD app

  1. Go to Azure Portal > App registrations
  2. Click New registration
  3. Set a name (e.g., "zend.sh") and register
  4. Under API permissions, add:
    • SMTP.Send (for sending)
    • IMAP.AccessAsUser.All (for reply detection)
  5. Under Certificates & secrets, create a client secret

Connect the mailbox

const account = await zend.accounts.create({
  email: 'outreach@yourcompany.com',
  provider: 'microsoft',
  smtp_host: 'smtp.office365.com',
  smtp_port: 587,
  smtp_username: 'outreach@yourcompany.com',
  smtp_password: 'your-password-or-token',
  imap_host: 'outlook.office365.com',
  imap_port: 993,
  imap_username: 'outreach@yourcompany.com',
  imap_password: 'your-password-or-token',
})

Custom SMTP/IMAP

Any email provider that supports SMTP and IMAP can be connected: Zoho, Namecheap, Fastmail, self-hosted, etc.

const account = await zend.accounts.create({
  email: 'outreach@yourcompany.com',
  provider: 'smtp',
  smtp_host: 'smtp.yourdomain.com',
  smtp_port: 465, // or 587 for STARTTLS
  smtp_username: 'outreach@yourcompany.com',
  smtp_password: 'your-password',
  imap_host: 'imap.yourdomain.com',
  imap_port: 993,
  imap_username: 'outreach@yourcompany.com',
  imap_password: 'your-password',
})

Common provider settings:

ProviderSMTP HostSMTP PortIMAP HostIMAP Port
Google Workspacesmtp.gmail.com465imap.gmail.com993
Microsoft 365smtp.office365.com587outlook.office365.com993
Zoho Mailsmtp.zoho.com465imap.zoho.com993
Namecheapmail.privateemail.com465mail.privateemail.com993

Validate DNS records

After connecting a mailbox, validate its SPF and DMARC records. DKIM is not checked by this endpoint (it returns dkim: { configured: false, pass: false, checked: false, reason: 'selector_required' } because no DKIM selector is available to it), so verify DKIM separately:

curl -X POST -H "Authorization: Bearer $ZEND_API_KEY" https://app.zend.sh/api/v1/accounts/{id}/validate

The result is wrapped in the standard response envelope, under data:

{
  "data": {
    "domain": "yourcompany.com",
    "spf": {
      "pass": false,
      "details": "Received-SPF: softfail (zend.sh: domain of transitioning validator@yourcompany.com does not designate 127.0.0.1 as permitted sender) client-ip=127.0.0.1; envelope-from=\"validator@yourcompany.com\"; helo=yourcompany.com;"
    },
    "dkim": { "configured": false, "pass": false, "checked": false, "reason": "selector_required" },
    "dmarc": { "configured": true, "policy": "reject", "pass": false }
  },
  "assessment": null,
  "insights": [],
  "recommendations": [],
  "warnings": [],
  "next_actions": []
}

Read the fields from data, for example jq .data.spf.details or jq .data.dmarc.policy.

This is what a correctly configured domain returns today, here with an SPF record ending in ~all and a p=reject DMARC record. The check evaluates SPF from 127.0.0.1, not from your provider's sending IP, so spf.pass and dmarc.pass are false even when your records are correct. Do not read pass: false as a misconfiguration on its own. Read these instead:

  • spf.details starts with Received-SPF: softfail (or fail for a record ending in -all) when your SPF record was found. none means no SPF record, and permerror means the record is broken, for example two SPF records on the domain.
  • dmarc.configured is true and dmarc.policy is your policy when your DMARC record was found.

An SPF TXT lookup failure (for example SERVFAIL) returns 502. A DMARC discovery failure returns 502 when no usable policy was found; DMARC temperror with a discovered policy still returns 200 with that policy. SPF permerror and missing SPF/DMARC records also return 200 verdicts.

The 502 response body has this shape (the SPF or DMARC message includes your domain):

{
  "type": "validation_failed",
  "message": "Domain validation failed: SPF discovery failed temporarily for yourcompany.com",
  "status": 502
}

For an unexpected validation error, the message is the fixed text Domain validation failed: an unexpected error occurred; resolver details and server hostnames are not returned.

Ensure your domain has proper DNS records:

  • SPF — Authorizes your mail server to send on behalf of your domain
  • DKIM — Digitally signs outgoing emails for authenticity
  • DMARC — Tells receiving servers how to handle unauthenticated email

Best practices

  1. Start with 2-3 accounts — Add more mailboxes as health scores stabilize above 80
  2. Use dedicated sending domains — Avoid using your primary business domain for cold outreach
  3. Set realistic daily limits — Start with 20-30 emails per account per day, increase gradually
  4. Monitor health scores — zend.sh auto-pauses accounts when bounce rates exceed 2% or spam complaints exceed 0.3%
  5. Warm up new accounts — Send small volumes to engaged contacts before scaling up cold outreach