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.
| Credential | Used As | Format |
|---|---|---|
| API Key | HTTP API key & SMTP username | nm_{company}_{hex} |
| API Secret | HTTP API secret & SMTP password | 32-character hex string |
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.
| Scenario | HTTP API | SMTP |
|---|---|---|
| Credits available | 200 Email accepted | 250 Message accepted |
| Credits exhausted | 429 Quota exceeded | 535 Auth failed |
| Account suspended | 403 Suspended | 535 Auth failed |
Send Email โ HTTP API
POST/send
https://api.neumails.com/send
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key | string | Yes | Your API key |
api_secret | string | Yes | Your API secret |
from | string | Yes | Sender email โ must match your verified sending domain. "Display Name <user@domain.com>" format is supported. |
to | string | Yes | Recipient email address(es) โ comma-separated for multiple |
cc NEW | string | No | Carbon-copy recipient(s) โ comma-separated. Visible to all recipients. |
bcc NEW | string | No | Blind carbon-copy recipient(s) โ comma-separated. Never shown in headers. |
subject | string | Yes | Email subject line |
html | string | Yes* | HTML body โ enables open & click tracking automatically |
text | string | Yes* | Plain text body (fallback for non-HTML clients) |
attachments | array | No | Up to 10 files, 30 MB total. See Attachments. |
metadata NEW | object | No | Custom 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
| Limit | Value | Response When Exceeded |
|---|---|---|
| Total recipients per request (to + cc + bcc) | 1,000 | 413 Too many recipients |
| Attachments per email | 10 files / 30 MB total | 400 / 413 |
| Metadata | 50 keys / 10 KB | 400 Invalid metadata |
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
}
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.
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>"
}'
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.
| Field | Header Visibility | Tracking & Quota |
|---|---|---|
to | Shown in To: header to all recipients | Individually tracked, 1 credit each |
cc | Shown in Cc: header to all recipients | Individually tracked, 1 credit each |
bcc | Never shown in headers โ invisible to other recipients | Individually 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>"
}'
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
| Rule | Value |
|---|---|
| Type | JSON object (not an array or scalar) |
| Max keys | 50 |
| Max size | 10 KB (serialized) |
| Scope | Per message โ shared by all recipients of the send |
| Invalid metadata | Request 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"
}
}
Error Handling
| Code | Error | What to Do |
|---|---|---|
| 400 | Missing/invalid fields, invalid metadata, invalid attachment | Fix the request payload โ the error message names the offending field |
| 401 | Invalid credentials | Check your API key and secret |
| 403 | Sender domain mismatch / account suspended | Send from your verified domain, or contact your account manager |
| 413 | Too many recipients (>1,000) or attachments exceed 30 MB | Split the send into smaller batches / reduce attachment size |
| 422 | All recipients suppressed | Release addresses from your suppression list |
| 429 | Quota exceeded | Add email credits or wait for renewal |
| 500 | Server error | Retry with exponential backoff |
| 503 | Server busy NEW | Temporary 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."
}
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
| Setting | Value |
|---|---|
| SMTP Host | smtp.neumails.com |
| Port (Recommended) | 587 โ STARTTLS |
| Port (Alternative) | 465 โ SMTPS / SSL |
| Authentication | LOGIN or PLAIN |
| Username | Your API Key (nm_yourcompany_xxx) |
| Password | Your API Secret |
| Max Message Size | 30 MB |
| Min TLS Version | TLS 1.2 |
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.
| Port | Encryption | How It Works | .NET EnableSsl |
|---|---|---|---|
587 โ
Recommended | STARTTLS | Connect plain, then upgrade to TLS automatically | false |
465 | SMTPS / SSL | Entire connection encrypted from the start | true |
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.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 = 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
| Platform | TLS 1.2 Support | Action Required |
|---|---|---|
| .NET Framework 4.6+ | โ Native | None โ works out of the box |
| .NET Framework 4.5 and below | โ ๏ธ Manual | Add ServicePointManager.SecurityProtocol = Tls12 |
| Python 3.4+ | โ Native | None |
| PHP 5.6+ / PHPMailer | โ Native | None |
| Node.js 12+ | โ Native | None |
| Java JDK 8u261+ | โ Native | None |
| Java JDK below 8u261 | โ ๏ธ Manual | Upgrade JDK or enable TLS 1.2 explicitly |
| Windows XP / Server 2003 | โ Not supported | OS 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 Type | MIME Type |
|---|---|
application/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 |
| ZIP | application/zip |
| Text / CSV | text/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"
}
]
}'
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.
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.
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 Type | Example |
|---|---|
| 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
| Channel | Behaviour |
|---|---|
| HTTP API โ multiple recipients | Suppressed 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 suppressed | Returns 422 โ nothing is sent. |
| SMTP | Message is accepted, suppressed recipients are blocked before delivery, and remaining recipients are unaffected. |
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 Size | Recommendation | DNS TXT Record Length |
|---|---|---|
| 2048-bit | Recommended โ stronger security, supported by all modern DNS providers | ~370 characters |
| 1024-bit | Use only if your DNS provider has a 255-character TXT record limit | ~190 characters |
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 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 Type | Action | Webhook Event |
|---|---|---|
| 2xx โ Delivered | Message accepted by recipient server | delivery |
| 4xx โ Temporary failure | Queued for retry using gradual backoff schedule | deferred per attempt; bounce if never delivered within the bounce window |
| 5xx โ Permanent failure | Immediately bounced, address suppressed | bounce |
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.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.
| Event | When It Fires |
|---|---|
injection | Email accepted by neuMails for delivery โ one event per recipient (including suppressed recipients) |
suppression NEW | A recipient was blocked by your suppression list โ includes suppression_reason and suppression_source |
delivery | Email successfully delivered to recipient's mail server โ includes DSN status and delivering source IP |
deferred NEW | Temporary (4xx) failure โ the message is queued for retry; includes DSN status and diagnostic text |
bounce | Email bounced โ includes DSN code, bounce category, and specific recipient address |
open | Recipient opened the email (HTML emails only) |
click | Recipient clicked a tracked link |
event_id, all sharing the same message_id.metadata object, every webhook event for that message includes the same metadata object. See Metadata Passthrough.Webhook Headers
| Header | Value |
|---|---|
Content-Type | application/json |
X-NM-Signature | HMAC-SHA256 hex digest of the raw body โ see Verification |
X-NM-Event NEW | The event type (e.g. delivery) โ route without parsing the body |
User-Agent | neuMails-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
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
| Type | Host | Value |
|---|---|---|
| TXT | yourdomain.com | v=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
| Type | Host | Value |
|---|---|---|
| TXT | s1._domainkey.yourdomain.com | Provided in portal โ copy from API Keys โ View Domain โ DKIM Record |
DMARC
| Type | Host | Value |
|---|---|---|
| TXT | _dmarc.yourdomain.com | v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com |
Response Codes
HTTP API
| Code | Meaning |
|---|---|
| 200 | Email accepted for delivery |
| 400 | Invalid request โ missing fields, bad metadata, or bad attachment |
| 401 | Invalid API key or secret |
| 403 | Sender domain does not match verified domain, or account suspended |
| 413 | Too many recipients (>1,000) or attachments over 30 MB |
| 422 | All recipients on suppression list |
| 429 | Email credit pool exhausted |
| 500 | Server error โ retry with backoff |
| 503 | Server busy โ retry after a short delay |
SMTP
| Code | Meaning |
|---|---|
| 235 | Authentication successful |
| 250 | Email accepted / recipient accepted |
| 451 | Temporary failure โ retry |
| 535 | Authentication failed โ check credentials or quota |
| 550 | Recipient suppressed or sending domain not verified |
Changelog
v3.2 โ July 10, 2026
cc and bcc fields on POST /send โ standard carbon-copy semantics with per-recipient tracking and suppression checkssuppression webhook event โ blocked recipients now fire injection + suppression events with block reason instead of being silently skipped (API and SMTP)deferred webhook event โ real-time visibility into temporary (4xx) failures and retry activity, with DSN status and diagnosticsX-NM-Event webhook header โ route events without parsing the bodyrecipients count/send responds as soon as the message is accepted; large recipient lists never time out the HTTP request; delivery confirmed via webhooksv3.1 โ April 27, 2026
465 (SMTPS) support โ full SSL from connection startEnableSsl clarification โ false required on port 587, true for port 465v3.0 โ March 25, 2026
to field supported in both HTTP API and SMTPevent_idv2.0 โ February 26, 2026
smtp.neumails.com:587 with STARTTLSv1.5 โ February 20, 2026
v1.0 โ February 10, 2026
POST /send endpoint