neuMails API

Send transactional emails at scale โ€” via HTTP API or SMTP. Built-in tracking, automatic bounce suppression, per-recipient event logging, metadata passthrough, and real-time webhooks.

Quick Start

Choose your preferred integration method. Both share the same credentials, tracking, and deliverability features.

โšก

HTTP API

Single POST /send endpoint. Send JSON, get instant response. Supports multiple recipients, CC/BCC, attachments, and custom metadata in one call. Best for applications and serverless functions.

๐Ÿ“ฎ

SMTP Relay

Standard SMTP on port 587 with STARTTLS. Drop-in replacement for any existing SMTP config. Requires TLS 1.2 or higher.

API Base URL: https://api.neumails.com
SMTP Server: smtp.neumails.com ยท Port 587 ยท STARTTLS ยท TLS 1.2+ required

Authentication

Your credentials are generated in the neuMails portal when you add a sending domain. A single credential pair works for both HTTP API and SMTP.

CredentialUsed AsFormat
API KeyHTTP API key & SMTP usernamenm_{company}_{hex}
API SecretHTTP API secret & SMTP password32-character hex string
Important: Your API secret is shown only once when generated. Store it securely. If lost, generate a new one from the portal โ€” the old secret will be invalidated immediately.
Sender domain enforcement: The from address must belong to the domain the credentials were issued for. Sending from any other domain returns HTTP 403 (API) or is rejected (SMTP).

Quotas

Each account has a credit pool that decrements in real time with every email sent. When the pool reaches zero, further sends are rejected until credits are added.

ScenarioHTTP APISMTP
Credits available200 Email accepted250 Message accepted
Credits exhausted429 Quota exceeded535 Auth failed
Account suspended403 Suspended535 Auth failed
Note: When sending to multiple recipients (including CC and BCC), each recipient counts as one email against your quota.

Send Email โ€” HTTP API

POST/send

https://api.neumails.com/send

Request Parameters

ParameterTypeRequiredDescription
api_keystringYesYour API key
api_secretstringYesYour API secret
fromstringYesSender email โ€” must match your verified sending domain. "Display Name <user@domain.com>" format is supported.
tostringYesRecipient email address(es) โ€” comma-separated for multiple
cc NEWstringNoCarbon-copy recipient(s) โ€” comma-separated. Visible to all recipients.
bcc NEWstringNoBlind carbon-copy recipient(s) โ€” comma-separated. Never shown in headers.
subjectstringYesEmail subject line
htmlstringYes*HTML body โ€” enables open & click tracking automatically
textstringYes*Plain text body (fallback for non-HTML clients)
attachmentsarrayNoUp to 10 files, 30 MB total. See Attachments.
metadata NEWobjectNoCustom JSON object (max 50 keys, 10 KB) echoed back in every webhook event for this message. See Metadata Passthrough.

* At least one of html or text is required. Send both for best deliverability.

Request Limits

LimitValueResponse When Exceeded
Total recipients per request (to + cc + bcc)1,000413 Too many recipients
Attachments per email10 files / 30 MB total400 / 413
Metadata50 keys / 10 KB400 Invalid metadata
Duplicate addresses across to, cc, and bcc are automatically de-duplicated โ€” each address receives exactly one copy and is charged once.

Example โ€” Single Recipient (cURL)

curl -X POST https://api.neumails.com/send \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "nm_yourcompany_abc123def456",
    "api_secret": "YOUR_API_SECRET",
    "from": "orders@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Order Confirmation #12345",
    "html": "<h1>Thank you for your order!</h1>"
  }'

Success Response

// HTTP 200
{
  "success": true,
  "message_id": "a3f8b2c17d4e",
  "recipients": 3
}
Asynchronous delivery v3.2: The API responds as soon as the message is accepted and logged โ€” delivery to recipient mail servers happens in the background. This means large recipient lists never block or time out your HTTP request. Actual delivery is confirmed per-recipient via delivery webhook events. The recipients field reports how many non-suppressed recipients were accepted for delivery.

Multiple Recipients

Both HTTP API and SMTP support sending to multiple recipients in a single request. Each recipient is tracked, logged, and suppression-checked independently.

Per-recipient tracking: Each recipient gets a unique event_id. Injections, deliveries, bounces, opens, and clicks are tracked individually โ€” not grouped. If one recipient bounces, only that address is suppressed.

HTTP API โ€” Multiple Recipients

Pass a comma-separated list of email addresses in the to field.

curl -X POST https://api.neumails.com/send \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "nm_yourcompany_abc123def456",
    "api_secret": "YOUR_API_SECRET",
    "from": "team@yourdomain.com",
    "to": "alice@example.com, bob@example.com, carol@example.com",
    "subject": "Team Update",
    "html": "<h1>Hello Team</h1>"
  }'
Suppression behaviour with multiple recipients CHANGED: Each address is checked individually against your suppression list. Suppressed addresses are skipped, and the email is still sent to all remaining recipients โ€” but skipped addresses are no longer silent: each one now generates an injection and a suppression webhook event and appears in your dashboard, so you have a full audit trail of why an address was not delivered. If all recipients are suppressed, a 422 is returned.

SMTP โ€” Multiple Recipients

Issue a separate RCPT TO command for each recipient, or pass a comma-separated list in the To header. neuMails logs each recipient individually.

// Node.js โ€” Nodemailer
await transporter.sendMail({
  from: 'team@yourdomain.com',
  to: 'alice@example.com, bob@example.com, carol@example.com',
  subject: 'Team Update',
  html: '<h1>Hello Team</h1>'
});

CC & BCC NEW in v3.2

The HTTP API now supports standard carbon-copy and blind-carbon-copy semantics.

FieldHeader VisibilityTracking & Quota
toShown in To: header to all recipientsIndividually tracked, 1 credit each
ccShown in Cc: header to all recipientsIndividually tracked, 1 credit each
bccNever shown in headers โ€” invisible to other recipientsIndividually tracked, 1 credit each
curl -X POST https://api.neumails.com/send \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "nm_yourcompany_abc123def456",
    "api_secret": "YOUR_API_SECRET",
    "from": "billing@yourdomain.com",
    "to": "customer@example.com",
    "cc": "accounts@example.com",
    "bcc": "audit@yourdomain.com",
    "subject": "Invoice #9001",
    "html": "<p>Invoice attached.</p>"
  }'
Each CC and BCC recipient receives their own privately-addressed copy, gets a unique event_id, and is suppression-checked independently โ€” while the visible To: and Cc: headers stay exactly as you specified. Opens and clicks are attributed to the individual recipient, even on CC/BCC copies.

Metadata Passthrough NEW in v3.2

Attach your own identifiers โ€” order IDs, customer IDs, campaign tags โ€” to any message. neuMails stores the object and echoes it back inside every webhook event generated by that message (injection, delivery, bounce, deferred, open, click), so you never need to maintain your own message_id lookup table.

Rules

RuleValue
TypeJSON object (not an array or scalar)
Max keys50
Max size10 KB (serialized)
ScopePer message โ€” shared by all recipients of the send
Invalid metadataRequest rejected with 400 before any email is sent

Example โ€” Send with Metadata

curl -X POST https://api.neumails.com/send \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "nm_yourcompany_abc123def456",
    "api_secret": "YOUR_API_SECRET",
    "from": "orders@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Order Confirmation #12345",
    "html": "<h1>Thank you!</h1>",
    "metadata": {
      "order_id": "ORD-12345",
      "customer_id": "CUST-8871",
      "campaign": "order-confirmation"
    }
  }'

Example โ€” Webhook Event with Metadata Echoed

{
  "event": "delivery",
  "event_id": "mm3b2983c14e07ea",
  "message_id": "a3f8b2c17d4e",
  "email": "customer@example.com",
  "subject": "Order Confirmation #12345",
  "dsn_status": "2.0.0",
  "timestamp": "2026-07-10T11:42:07.000Z",
  "metadata": {
    "order_id": "ORD-12345",
    "customer_id": "CUST-8871",
    "campaign": "order-confirmation"
  }
}
Metadata passthrough is available on the HTTP API. Messages sent via SMTP relay do not carry custom metadata.

Error Handling

CodeErrorWhat to Do
400Missing/invalid fields, invalid metadata, invalid attachmentFix the request payload โ€” the error message names the offending field
401Invalid credentialsCheck your API key and secret
403Sender domain mismatch / account suspendedSend from your verified domain, or contact your account manager
413Too many recipients (>1,000) or attachments exceed 30 MBSplit the send into smaller batches / reduce attachment size
422All recipients suppressedRelease addresses from your suppression list
429Quota exceededAdd email credits or wait for renewal
500Server errorRetry with exponential backoff
503Server busy NEWTemporary backpressure under peak load โ€” retry after a short delay

Suppression Error โ€” Example

// HTTP 422 โ€” all recipients suppressed
{
  "error": "All recipients are suppressed",
  "message": "All recipients have previously hard-bounced. Release from suppression list to send again."
}
Partial suppression is not an error CHANGED: When only some recipients are suppressed, the API still returns HTTP 200 and delivers to the remaining recipients. Each skipped address fires injection + suppression webhook events with the block reason โ€” see Webhook Events.

SMTP Relay

SMTPsmtp.neumails.com:587

Use neuMails as your SMTP relay โ€” compatible with any application, language, or email client. All emails sent via SMTP receive automatic open tracking, click tracking, bounce suppression, and per-recipient event logging.

Connection Settings

SettingValue
SMTP Hostsmtp.neumails.com
Port (Recommended)587 โ€” STARTTLS
Port (Alternative)465 โ€” SMTPS / SSL
AuthenticationLOGIN or PLAIN
UsernameYour API Key (nm_yourcompany_xxx)
PasswordYour API Secret
Max Message Size30 MB
Min TLS VersionTLS 1.2
Username format: SMTP usernames always begin with nm_. Repeated authentication attempts with malformed usernames or wrong passwords will result in a temporary IP ban. If your connection suddenly starts timing out after failed logins, wait 30 minutes and verify your credentials before retrying.

TLS Requirements & Port Guide

neuMails SMTP requires TLS 1.2 or higher. TLS 1.0 and TLS 1.1 are not supported. Two ports are available depending on your application's SSL mode.

PortEncryptionHow It Works.NET EnableSsl
587 โœ… RecommendedSTARTTLSConnect plain, then upgrade to TLS automaticallyfalse
465SMTPS / SSLEntire connection encrypted from the starttrue
.NET Port 587 โ€” Critical: On port 587 (STARTTLS), set EnableSsl = false. The connection upgrades to TLS automatically after connecting. Setting EnableSsl = true on port 587 causes a "Server does not support secure connections" error because your application looks for an SSL handshake that does not happen on this port.
Port 465 alternative: If your application requires EnableSsl = true and cannot be changed, use port 465 instead. Both ports use full TLS encryption โ€” only the handshake timing differs.

.NET Framework Fix

Old .NET Framework (4.5 and below) defaults to TLS 1.0. Add this line before creating your SmtpClient:

// Add BEFORE SmtpClient initialization
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

// Port 587 โ€” STARTTLS (recommended)
SmtpClient client = new SmtpClient("smtp.neumails.com", 587);
client.EnableSsl = false;  // IMPORTANT โ€” false for port 587
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("nm_yourcompany_xxx", "YOUR_SECRET");
client.DeliveryMethod = SmtpDeliveryMethod.Network;

// Port 465 โ€” SMTPS (if your app requires EnableSsl = true)
// SmtpClient client = new SmtpClient("smtp.neumails.com", 465);
// client.EnableSsl = true;
UseDefaultCredentials: Always set UseDefaultCredentials = false before setting Credentials. Setting it to true causes .NET to attempt Windows SSPI authentication (NTLM/Kerberos) instead of SMTP LOGIN, which will fail.

TLS Compatibility by Platform

PlatformTLS 1.2 SupportAction Required
.NET Framework 4.6+โœ… NativeNone โ€” works out of the box
.NET Framework 4.5 and belowโš ๏ธ ManualAdd ServicePointManager.SecurityProtocol = Tls12
Python 3.4+โœ… NativeNone
PHP 5.6+ / PHPMailerโœ… NativeNone
Node.js 12+โœ… NativeNone
Java JDK 8u261+โœ… NativeNone
Java JDK below 8u261โš ๏ธ ManualUpgrade JDK or enable TLS 1.2 explicitly
Windows XP / Server 2003โŒ Not supportedOS upgrade required

SMTP โ€” Code Examples

Python

# Python 3.x
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

msg = MIMEMultipart('alternative')
msg['From'] = 'orders@yourdomain.com'
msg['To'] = 'customer@example.com'
msg['Subject'] = 'Order Confirmation'
msg.attach(MIMEText('<h1>Thank you!</h1>', 'html'))

context = ssl.create_default_context()
with smtplib.SMTP('smtp.neumails.com', 587) as server:
    server.starttls(context=context)
    server.login('nm_yourcompany_abc123def456', 'YOUR_API_SECRET')
    server.send_message(msg)

Node.js

// Nodemailer
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.neumails.com',
  port: 587,
  secure: false,  // false = STARTTLS on port 587
  auth: {
    user: 'nm_yourcompany_abc123def456',
    pass: 'YOUR_API_SECRET'
  }
});

await transporter.sendMail({
  from: 'orders@yourdomain.com',
  to: 'customer@example.com',
  subject: 'Order Confirmation',
  html: '<h1>Thank you!</h1>'
});

PHP (PHPMailer)

// PHPMailer
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host       = 'smtp.neumails.com';
$mail->SMTPAuth   = true;
$mail->Username   = 'nm_yourcompany_abc123def456';
$mail->Password   = 'YOUR_API_SECRET';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port       = 587;

$mail->setFrom('orders@yourdomain.com');
$mail->addAddress('customer@example.com');
$mail->isHTML(true);
$mail->Subject = 'Order Confirmation';
$mail->Body    = '<h1>Thank you!</h1>';
$mail->send();

.NET (C#)

// .NET โ€” correct configuration for neuMails (port 465, EnableSsl = true)
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

SmtpClient client = new SmtpClient("smtp.neumails.com", 465);
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(
    "nm_yourcompany_abc123def456",
    "YOUR_API_SECRET"
);
client.DeliveryMethod = SmtpDeliveryMethod.Network;

MailMessage mail = new MailMessage();
mail.From = new MailAddress("orders@yourdomain.com");
mail.To.Add("customer@example.com");
mail.Subject = "Order Confirmation";
mail.Body = "<h1>Thank you!</h1>";
mail.IsBodyHtml = true;
client.Send(mail);

Java

// Jakarta Mail
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.neumails.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.ssl.protocols", "TLSv1.2");

Session session = Session.getInstance(props, new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(
            "nm_yourcompany_abc123def456", "YOUR_API_SECRET");
    }
});

Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("orders@yourdomain.com"));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("customer@example.com"));
msg.setSubject("Order Confirmation");
msg.setContent("<h1>Thank you!</h1>", "text/html");
Transport.send(msg);

Ruby

# Net::SMTP with TLS 1.2
require 'net/smtp'

message = <<~MSG
From: orders@yourdomain.com
To: customer@example.com
Subject: Order Confirmation
Content-Type: text/html

<h1>Thank you!</h1>
MSG

smtp = Net::SMTP.new('smtp.neumails.com', 587)
smtp.enable_starttls
smtp.start('yourdomain.com', 'nm_yourcompany_abc123def456',
           'YOUR_API_SECRET', :login) do |s|
  s.send_message(message, 'orders@yourdomain.com', 'customer@example.com')
end

Attachments

Both HTTP API and SMTP support file attachments. Maximum total size is 30 MB per email with up to 10 attachments.

Allowed File Types

File TypeMIME Type
PDFapplication/pdf
Word (.docx / .doc)application/vnd.openxmlformats-officedocument.wordprocessingml.document
Excel (.xlsx / .xls)application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
PowerPoint (.pptx)application/vnd.openxmlformats-officedocument.presentationml.presentation
ZIPapplication/zip
Text / CSVtext/plain / text/csv
Images (JPEG / PNG / GIF / WEBP)image/jpeg / image/png / image/gif / image/webp

HTTP API โ€” Attachment Example

curl -X POST https://api.neumails.com/send \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "nm_yourcompany_abc123def456",
    "api_secret": "YOUR_API_SECRET",
    "from": "billing@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Invoice #12345",
    "html": "<p>Please find your invoice attached.</p>",
    "attachments": [
      {
        "filename": "invoice_12345.pdf",
        "content": "JVBERi0xLjQ...(base64 encoded content)...",
        "content_type": "application/pdf"
      }
    ]
  }'
Encoding: Attachment content must be base64 encoded. The content_type field must match one of the allowed MIME types above. Files with unsupported MIME types, missing filename/content fields, or non-base64 encodings will be rejected with a 400 error.

Open Tracking

A transparent 1ร—1 tracking pixel is automatically injected into every HTML email. When the recipient opens the email and images load, an open event is recorded and sent to your webhook.

Automatic: No code changes needed. Open tracking works for both HTTP API and SMTP as long as the email has an HTML body. Plain-text only emails do not get a tracking pixel.

Open events include the recipient's IP address and user agent. Opens are attributed per-recipient โ€” including individual CC and BCC recipients. Some email clients preload images through proxies, which may result in multiple open events per email โ€” this is expected behavior.

Click Tracking

All https:// links in your HTML body are automatically rewritten to tracking URLs. When a recipient clicks, the event is recorded and they are instantly redirected (HTTP 302) to the original destination.

Automatic: No code changes needed. Tracking URLs are transparent โ€” the recipient lands on the original URL. Internal links and mailto: links are not rewritten.

Click events include the original target URL, recipient's IP address, and user agent. Each unique link in a message gets a separate tracking ID, and clicks are attributed to the individual recipient who clicked.

Suppression List

When an email hard-bounces, the recipient address is automatically added to your suppression list. Future sends to that address are blocked before delivery, protecting your sender reputation.

What Gets Suppressed

Bounce TypeExample
Invalid mailbox"550 5.1.1 User unknown"
Inactive account"550 5.2.1 Mailbox disabled"
Non-existent domain"550 5.4.4 Domain not found"

Managing Suppressions

From the neuMails portal you can view all suppressed addresses with bounce reason and date, release individual or multiple addresses, manually add addresses, and export the full list as CSV.

Pre-Send Behaviour

ChannelBehaviour
HTTP API โ€” multiple recipientsSuppressed addresses are skipped; email is sent to remaining recipients. 200 returned with recipients reflecting the delivered count. 422 only if all are suppressed.
HTTP API โ€” all recipients suppressedReturns 422 โ€” nothing is sent.
SMTPMessage is accepted, suppressed recipients are blocked before delivery, and remaining recipients are unaffected.
Suppression events NEW in v3.2: Every skipped recipient โ€” on both HTTP API and SMTP โ€” now generates two webhook events and two dashboard entries: an injection event (the send reached neuMails) and a suppression event carrying suppression_reason and suppression_source. This gives you a complete per-recipient audit trail: you can see exactly which addresses were blocked, when, and why, without reconciling against your own logs. Subscribe to the suppression event in your webhook settings (enabled by default for new webhook configurations).

DKIM Key Management

neuMails supports both 1024-bit and 2048-bit RSA DKIM keys. You can select your preferred key size from the API Key Details page in the portal and regenerate at any time.

Choosing a Key Size

Key SizeRecommendationDNS TXT Record Length
2048-bitRecommended โ€” stronger security, supported by all modern DNS providers~370 characters
1024-bitUse only if your DNS provider has a 255-character TXT record limit~190 characters
After regenerating: You must update your DNS TXT record (s1._domainkey.yourdomain.com) with the new public key. Email delivery will fail DKIM verification until the DNS record is updated. DNS propagation typically takes a few minutes to a few hours.

How to Regenerate

Go to Portal โ†’ API Keys โ†’ View Domain โ†’ DKIM Record. Select the desired key size from the dropdown and click Regenerate DKIM. The new key is deployed to the sending infrastructure automatically.

Delivery & Retry Policy

When an email cannot be delivered immediately due to a temporary failure (4xx response from the receiving mail server), neuMails automatically retries delivery with a gradually increasing interval. Permanent failures (5xx) are bounced immediately without retrying.

Deferred visibility NEW in v3.2: Each temporary failure now generates a real-time deferred webhook event with the receiving server's DSN status and diagnostic text, so you can see retry activity as it happens instead of waiting for the final delivery or bounce.

How Retries Work

Response TypeActionWebhook Event
2xx โ€” DeliveredMessage accepted by recipient serverdelivery
4xx โ€” Temporary failureQueued for retry using gradual backoff scheduledeferred per attempt; bounce if never delivered within the bounce window
5xx โ€” Permanent failureImmediately bounced, address suppressedbounce
Bounce window: If an email cannot be delivered within the retry window after the first attempt, neuMails stops retrying and records a bounce event. The address is added to your suppression list if the final failure is permanent. Transactional traffic uses a front-loaded schedule โ€” the first retries happen within minutes of a temporary failure so short-lived issues at the receiving server delay your mail as little as possible.
Bounce suppression: Addresses that result in a permanent bounce (5xx) are automatically added to your suppression list. Future sends to those addresses are blocked before delivery. See Suppression List for details.

Webhook Events

neuMails sends real-time event notifications to your webhook URL as HTTP POST requests with a JSON payload. Configure your webhook URL and event subscriptions in the portal under domain settings.

EventWhen It Fires
injectionEmail accepted by neuMails for delivery โ€” one event per recipient (including suppressed recipients)
suppression NEWA recipient was blocked by your suppression list โ€” includes suppression_reason and suppression_source
deliveryEmail successfully delivered to recipient's mail server โ€” includes DSN status and delivering source IP
deferred NEWTemporary (4xx) failure โ€” the message is queued for retry; includes DSN status and diagnostic text
bounceEmail bounced โ€” includes DSN code, bounce category, and specific recipient address
openRecipient opened the email (HTML emails only)
clickRecipient clicked a tracked link
Per-recipient events: All events are per-recipient. When sending to multiple recipients, each recipient generates independent events with their own unique event_id, all sharing the same message_id.
Metadata echo NEW: If the message was sent via the HTTP API with a metadata object, every webhook event for that message includes the same metadata object. See Metadata Passthrough.
Event filtering: You can subscribe to a subset of events per domain in the portal. Only subscribed event types are delivered to your endpoint.

Webhook Headers

HeaderValue
Content-Typeapplication/json
X-NM-SignatureHMAC-SHA256 hex digest of the raw body โ€” see Verification
X-NM-Event NEWThe event type (e.g. delivery) โ€” route without parsing the body
User-AgentneuMails-Webhook/2.0

Example Payload โ€” Delivery Event

{
  "event": "delivery",
  "event_id": "mm3b2983c14e07ea",
  "message_id": "a3f8b2c17d4e",
  "email": "customer@example.com",
  "from": "orders@yourdomain.com",
  "subject": "Order Confirmation #12345",
  "dsn_status": "2.0.0",
  "source_ip": "x.x.x.x",
  "timestamp": "2026-07-10T11:42:07.000Z",
  "metadata": { "order_id": "ORD-12345" }
}

Example Payload โ€” Suppression Event NEW

{
  "event": "suppression",
  "event_id": "mm3b2983c14e07ec",
  "message_id": "a3f8b2c17d4e",
  "email": "bounced-user@example.com",
  "from": "orders@yourdomain.com",
  "subject": "Order Confirmation #12345",
  "suppression_reason": "hard_bounce",
  "suppression_source": "bounce",
  "timestamp": "2026-07-10T11:42:05.000Z"
}

Example Payload โ€” Deferred Event NEW

{
  "event": "deferred",
  "event_id": "mm3b2983c14e07ed",
  "message_id": "a3f8b2c17d4e",
  "email": "customer@example.com",
  "from": "orders@yourdomain.com",
  "subject": "Order Confirmation #12345",
  "dsn_status": "4.7.0",
  "dsn_diag": "451 4.7.0 Try again later",
  "timestamp": "2026-07-10T11:45:12.000Z"
}

Example Payload โ€” Bounce Event

{
  "event": "bounce",
  "event_id": "mm3b2983c14e07eb",
  "message_id": "a3f8b2c17d4e",
  "email": "bounced-user@example.com",
  "bounce_type": "hard",
  "bounce_category": "bad-mailbox",
  "dsn_status": "5.1.1",
  "dsn_diag": "550 5.1.1 User unknown",
  "timestamp": "2026-07-10T11:43:02.000Z"
}

Example Payload โ€” Click Event

{
  "event": "click",
  "event_id": "mm3b2983c14e07ee",
  "message_id": "a3f8b2c17d4e",
  "email": "customer@example.com",
  "subject": "Order Confirmation #12345",
  "link_url": "https://yourdomain.com/order/12345",
  "timestamp": "2026-07-10T12:01:59.000Z",
  "ip": "203.0.113.42",
  "user_agent": "Mozilla/5.0..."
}

Webhook Verification

Every webhook includes an X-NM-Signature header โ€” an HMAC-SHA256 hex digest of the raw JSON body, signed with your webhook secret.

// Node.js verification
const crypto = require('crypto');
const expected = crypto
  .createHmac('sha256', YOUR_WEBHOOK_SECRET)
  .update(rawRequestBody)
  .digest('hex');

if (expected === req.headers['x-nm-signature']) {
  // Verified โ€” process event
}
# Python verification
import hmac, hashlib

expected = hmac.new(
    WEBHOOK_SECRET.encode(), raw_body, hashlib.sha256
).hexdigest()

if hmac.compare_digest(expected, request.headers['X-NM-Signature']):
    # Verified
Retry policy: Failed webhook deliveries (non-2xx response) are retried up to 12 times with exponential backoff over an 8-hour window. After all retries are exhausted, the event is marked as failed and visible in the portal under Webhooks โ†’ Batch Status.

DNS Records

Before sending, verify your domain by adding these DNS records. The neuMails portal provides the exact values for your domain under API Keys โ†’ View Domain.

SPF

TypeHostValue
TXTyourdomain.comv=spf1 include:neumails.com ~all

If you already have an SPF record, merge it by adding include:neumails.com before the ~all or -all. Do not create a second SPF record.

DKIM

TypeHostValue
TXTs1._domainkey.yourdomain.comProvided in portal โ€” copy from API Keys โ†’ View Domain โ†’ DKIM Record
Key size note: If your DNS provider has a TXT record character limit, use the 1024-bit key option from the portal. See DKIM Key Management for details.

DMARC

TypeHostValue
TXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com
Tip: After adding DNS records, click Verify DNS in the portal. Verification typically completes within a few minutes to a few hours depending on your DNS provider's TTL.

Response Codes

HTTP API

CodeMeaning
200Email accepted for delivery
400Invalid request โ€” missing fields, bad metadata, or bad attachment
401Invalid API key or secret
403Sender domain does not match verified domain, or account suspended
413Too many recipients (>1,000) or attachments over 30 MB
422All recipients on suppression list
429Email credit pool exhausted
500Server error โ€” retry with backoff
503Server busy โ€” retry after a short delay

SMTP

CodeMeaning
235Authentication successful
250Email accepted / recipient accepted
451Temporary failure โ€” retry
535Authentication failed โ€” check credentials or quota
550Recipient suppressed or sending domain not verified

Changelog

v3.2 โ€” July 10, 2026

NEW cc and bcc fields on POST /send โ€” standard carbon-copy semantics with per-recipient tracking and suppression checks
NEW Metadata passthrough โ€” attach a custom JSON object (up to 50 keys / 10 KB) to any API send; echoed back in every webhook event for the message
NEW suppression webhook event โ€” blocked recipients now fire injection + suppression events with block reason instead of being silently skipped (API and SMTP)
NEW deferred webhook event โ€” real-time visibility into temporary (4xx) failures and retry activity, with DSN status and diagnostics
NEW X-NM-Event webhook header โ€” route events without parsing the body
NEW Recipient limit โ€” up to 1,000 recipients per API request (413 when exceeded); success response now includes a recipients count
IMPROVED Asynchronous accept โ€” /send responds as soon as the message is accepted; large recipient lists never time out the HTTP request; delivery confirmed via webhooks
IMPROVED Suppressed recipients now appear in the dashboard with full injection + suppression logging for a complete per-recipient audit trail
IMPROVED Front-loaded retry schedule for transactional mail โ€” first retries within minutes of a temporary failure
IMPROVED Duplicate recipients across to/cc/bcc are automatically de-duplicated
FIX Bounce, delivery, and deferred events now always report the exact recipient address from the receiving server, even on multi-recipient sends
FIX New 503 response under peak load with clear retry guidance, replacing opaque timeouts

v3.1 โ€” April 27, 2026

NEW SMTP port 465 (SMTPS) support โ€” full SSL from connection start
NEW Attachment support โ€” up to 10 files, 30 MB total, via HTTP API and SMTP
IMPROVED Max message size increased from 25 MB to 30 MB
IMPROVED Port guide โ€” clear documentation of STARTTLS (587) vs SMTPS (465) behavior
FIX .NET EnableSsl clarification โ€” false required on port 587, true for port 465
FIX TLS compatibility for legacy .NET and Java applications using old SSL certificate chains

v3.0 โ€” March 25, 2026

NEW Multiple recipients โ€” comma-separated to field supported in both HTTP API and SMTP
NEW Per-recipient event tracking โ€” each recipient gets a unique event_id
NEW DKIM key size selector โ€” choose 1024-bit or 2048-bit from the portal
NEW Per-recipient suppression on multi-recipient sends
IMPROVED Delivery retry โ€” gradual backoff over the bounce window
IMPROVED Webhook retry โ€” up to 12 attempts with exponential backoff over 8 hours

v2.0 โ€” February 26, 2026

NEW SMTP relay โ€” send via smtp.neumails.com:587 with STARTTLS
NEW Automatic open & click tracking for SMTP sends
NEW SMTP suppression check โ€” blocked recipients rejected at connection time
IMPROVED Unified credentials โ€” same key/secret for both API and SMTP

v1.5 โ€” February 20, 2026

NEW Automatic suppression โ€” hard bounces blocked from future sends
NEW Suppression management in portal โ€” view, release, bulk release, manual add, CSV export

v1.0 โ€” February 10, 2026

NEW HTTP API โ€” POST /send endpoint
NEW Open & click tracking, real-time webhooks, DNS verification (SPF, DKIM, DMARC)