Everything you need to integrate and extend Mailtr.
Getting Started
Introduction
Mailtr is a visual email builder that generates clean, responsive HTML compatible with all major email clients. Whether you are a marketer building campaigns or a developer integrating our editor into your SaaS, this documentation will guide you through the process.
New here? Follow the Quick Start to go from sign-up to a sent email in a few minutes, then dip into the API Reference when you are ready to send from code.
Installation
There is nothing to install. Mailtr runs in your browser — create a free account and the editor, template library and dashboard are ready to use.
Sending from your own code needs no SDK either. The HTTP API works with any HTTP client, and the SMTP relay works with any mail library — nodemailer, Python’s smtplib, or your framework’s mailer.
Editor: any modern desktop browser.
HTTP API: an API key and the base URL https://api.mailtr.co/api/v1.
SMTP relay: SMTP credentials from Dashboard → SMTP & API.
Start from a design in the Marketplace or from a blank canvas.
Build your email in the drag & drop editor — sections, rows and blocks.
Press Publish on the template’s card to make it the live version.
Export the HTML, or generate an API key in Dashboard → SMTP & API and send it with POST /api/v1/emails/send and its templateId.
Core Concepts
Drag & Drop Editor
The editor is built on a block-based system. Every element in the email (text, image, button, spacer) is a "Block". Blocks are stacked vertically within "Sections" or "Columns".
Sections: Full-width containers that hold rows.
Rows: Horizontal containers that can be split into columns (1-4).
Blocks: The actual content elements.
Using Templates
Templates are reusable designs you build in the editor. Start from one in our marketplace or save your own, then reuse it across sends.
To send a template programmatically, publish it and pass its templateId to the API — see Sending with a template.
Exporting HTML
Our renderer ensures high compatibility. When you export, we:
Inline all CSS styles automatically.
Convert modern layout properties (Flexbox/Grid) into ghost tables for Outlook.
Compress images and optimize assets.
API Reference
Send transactional email over HTTP or SMTP. All requests are made against the base URL https://api.mailtr.co/api/v1. The programmatic sending feature must be enabled on your account.
Authentication
The HTTP API authenticates with an API key. Generate one from Dashboard → SMTP & API. Keys look like mailtr_live_… and are shown only once at creation. Send it as a Bearer token:
Keep your key secret. API keys grant sending access to your account. Store them in server-side environment variables — never embed a key in client-side code. Revoke and rotate keys from the dashboard if one is exposed.
Endpoints
Send an email
POST /api/v1/emails/send — queues a message to one or more recipients. The from address must be one of your verified senders.
Several recipients normally share one message, so they can see each other in the To: header. If your body carries an unsubscribe link, we send one message per recipient instead — each with its own working opt-out link and List-Unsubscribe header — and recipients no longer see each other. A link that identifies one person cannot live in a body several people share, which is the whole reason the two differ.
Field
Type
Required
Description
from
string
Yes
Verified sender, as “Name <email@domain>” or a bare address.
to
string[]
Yes
One or more recipient email addresses (up to 1000 per request). Sent as one shared message, or one message each when the body carries an unsubscribe link.
subject
string
Yes*
Required unless a template supplies one.
html
string
—
HTML body. Provide html or text (or a templateId).
text
string
—
Plain-text body / fallback. Auto-derived from html if omitted.
templateId
string
—
Published template id. Uses the template's HTML + subject.
variables
object
—
Key/value pairs interpolated into {{placeholders}}.
trackOpens
boolean
—
Default false. Injects a 1×1 open-tracking pixel.
trackClicks
boolean
—
Default false. Rewrites http(s) links for click tracking.
Pass a published templateId instead of html. Any {{variables}} in the template are filled from the variables object. The template's subject is used unless you override it.
Write {{orderId}} anywhere in the template's content or subject, then declare it in the editor's Variables panel — that declaration is what decides how a send behaves when a value is missing:
Case
What happens
You supply a value
It replaces the placeholder. Values are escaped, so they can't inject markup.
You omit it, but it has a default
The declared default is used.
You omit it, and it is marked required
The send is rejected (HTTP 400 / SMTP 550) rather than delivered with a hole in it.
The placeholder was never declared
It is removed from the sent email — a raw {{token}} never reaches an inbox.
Links, images, lists and conditions
A variable works in a button's label and link, and in an image's source, alt text and link — use the { } button beside each field. A variable that starts a link is the whole link ({{ctaUrl}}); one inside it is URL-encoded (https://shop.example/o/{{orderId}}). A filled-in link must be http, https, mailto or tel, and an image http or https; anything else is removed. Links stay click-tracked.
Declare a List variable and choose it under a block's Show & repeat settings to repeat that block once per item, up to 100 — inside it, write {{item.name}}. Any block can also be shown only when a value has one, equals something, or is over or under a number. Send a list as a JSON array and an Object as a JSON object; values can be formatted with {{ total | currency: 'USD' }}, {{ name | default: 'there' }} or {{ sentAt | date: '%b %d' }}. Templates use Liquid syntax, and plain {{name}} variables work exactly as before.
Editing a published template does not change what your sends use. Your changes are held in a working draft, and the live version keeps going out until you press Publish on the template's card.
Prefer SMTP? Generate SMTP credentials from Dashboard → SMTP & API and point any mail library at our relay. The exact host and port are shown on that page. SMTP sends share the same quota, logs, and stats as the HTTP API.
Host
send.mailtr.co
Port
587 (STARTTLS) or 465 (SSL/TLS)
Username
your generated SMTP username
Password
your generated SMTP password
Node.js (nodemailer)
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "send.mailtr.co",
port: 587,
secure: false, // STARTTLS on 587; set true for 465
auth: {
user: process.env.MAILTR_SMTP_USER,
pass: process.env.MAILTR_SMTP_PASS,
},
});
await transporter.sendMail({
from: '"Jane" <jane@yourdomain.com>',
to: "recipient@example.com",
subject: "Welcome to Mailtr",
html: "<h1>Hello!</h1>",
});
Templates & variables over SMTP
SMTP has no request body to put a templateId in, so both travel as headers. They are the exact counterparts of the API's templateId and variables fields, and the rules in the table above apply identically.
Header
Value
X-Mailtr-Template-Id
Published template id, e.g. tpl_aB3xK9mZ. The template's HTML and subject are used.
X-Mailtr-Variables
A JSON object, e.g. {"orderId":"1234"}. Malformed JSON is rejected with a 550 rather than sent with blank placeholders.
Your mail library may MIME-encode the variables header, since JSON is full of characters headers don't normally carry. That is fine — we decode it either way, so just pass the JSON as-is.
await transporter.sendMail({
from: '"Jane" <jane@yourdomain.com>',
to: "recipient@example.com",
// No html/subject needed — the template supplies both.
headers: {
"X-Mailtr-Template-Id": "tpl_aB3xK9mZ",
"X-Mailtr-Variables": JSON.stringify({
firstName: "Sam",
orderId: "1234",
}),
},
});
Tracking & bounces
Open and click tracking are opt-in per send (trackOpens / trackClicks), default off. When enabled we modify the sent HTML — a 1×1 pixel for opens, link rewriting for clicks — and surface the results in your Transactional logs and stats.
Tracking respects recipient consent: if any recipient of a send has opted out of tracking, both trackOpens and trackClicks are disabled for that entire send, even if you set them true.
Every send is recorded in Transactional → Logs with its delivery status (queued → sent → delivered → opened).
Hard bounces automatically add the recipient to your suppression list; soft bounces are recorded only.
Sends to a suppressed address are dropped, and a request whose recipients are all suppressed is rejected with 400.
Errors & limits
Errors return a non-2xx status with a JSON body describing the problem.
Status
Meaning
400
Validation failed, missing content, or all recipients suppressed.
401
Missing or invalid API key.
403
Programmatic sending is not enabled for your account.
429
Rate limit or per-email recipient limit exceeded (plan-based).
Full API Reference Coming Soon
Sending is live today. We are putting the finishing touches on the rest of our public API — soon you’ll be able to programmatically generate emails, manage templates, and sync subscribers.