Verify your domain
Add and verify your sending domain in the dashboard before production traffic.
Authenticate with API keys and send transactional email through POST /api/v1/message.
Add and verify your sending domain in the dashboard before production traffic.
Generate an API key scoped to your verified domain and store it securely.
Call POST /api/v1/message with JSON and your Bearer token.
Include your API key in the Authorization header on every request.
1
Authorization: Bearer <YOUR_API_KEY>
Send JSON with a sender, recipients, and either HTML or text content. Requests must include application/json.
Need a starting point? Browse the transactional email templates.
POST /api/v1/message
Base URL https://mailsurge.dev
1
curl -X POST "https://mailsurge.dev/api/v1/message" \
2
-H "Authorization: Bearer YOUR_API_KEY" \
3
-H "Content-Type: application/json" \
4
-d '{
5
"from": "Sender <no-reply@yourdomain.com>",
6
"to": ["user@example.com"],
7
"subject": "Hello from Mailsurge",
8
"html": "<p>Hi there 👋</p>",
9
"text": "Hi there",
10
"headers": {
11
"X-Campaign": "welcome"
12
},
13
"attachments": [
14
{
15
"filename": "hello.txt",
16
"content": "SGVsbG8gd29ybGQh",
17
"content_type": "text/plain",
18
"disposition": "attachment"
19
}
20
]
21
}'
1
import Mailsurge from '@mailsurge/node';
2
3
const mailsurge = new Mailsurge();
4
5
await mailsurge.messages.send({
6
from: 'Sender <no-reply@yourdomain.com>',
7
to: ['user@example.com'],
8
subject: 'Hello from Mailsurge',
9
html: '<p>Hi there 👋</p>',
10
text: 'Hi there',
11
headers: {
12
'X-Campaign': 'welcome',
13
},
14
attachments: [
15
{
16
filename: 'hello.txt',
17
content: 'SGVsbG8gd29ybGQh',
18
content_type: 'text/plain',
19
disposition: 'attachment',
20
},
21
],
22
});
1
from mailsurge import Mailsurge
2
3
with Mailsurge() as client:
4
client.messages.send(
5
from_='Sender <no-reply@yourdomain.com>',
6
to=['user@example.com'],
7
subject='Hello from Mailsurge',
8
html='<p>Hi there 👋</p>',
9
text='Hi there',
10
headers={'X-Campaign': 'welcome'},
11
attachments=[
12
{
13
'filename': 'hello.txt',
14
'content': 'SGVsbG8gd29ybGQh',
15
'content_type': 'text/plain',
16
'disposition': 'attachment',
17
},
18
],
19
)
1
Http::withToken(env('MAILSURGE_API_KEY'))
2
->post('https://mailsurge.dev/api/v1/message', [
3
'from' => 'Sender <no-reply@yourdomain.com>',
4
'to' => ['user@example.com'],
5
'subject' => 'Hello from Mailsurge',
6
'html' => '<p>Hi there 👋</p>',
7
'text' => 'Hi there',
8
'headers' => [
9
'X-Campaign' => 'welcome',
10
],
11
'attachments' => [
12
[
13
'filename' => 'hello.txt',
14
'content' => 'SGVsbG8gd29ybGQh',
15
'content_type' => 'text/plain',
16
'disposition' => 'attachment',
17
],
18
],
19
]);
from (string, required): Sender address, e.g. Sender Name <no-reply@yourdomain.com>.
to (string|array, required): Recipient email or array of emails.
subject (string, required): Message subject line.
html (string, optional): HTML body.
text (string, optional): Plain text body.
cc (string|array, optional)
bcc (string|array, optional)
reply_to (string|array, optional)
headers (object, optional): Custom headers, e.g. {"X-Campaign": "welcome"}.
attachments (array, optional): Each item supports filename, content (base64 or raw text), content_type, disposition (attachment or inline), and content_id for inline images.
201 Created on success with an empty body (message is queued for delivery).
401 Unauthorized with {"reason": "Invalid key"}.
402 Payment Required when the account has no active subscription.
403 Forbidden when the account is blocked or pending approval.
400 Bad Request when the from domain is invalid or not verified.
413 Payload Too Large when attachments exceed 20MB or the queue payload exceeds 1MB.
422 Unprocessable Entity with validation errors for invalid input.
429 Too Many Requests when new account sending limits are reached.
html or text.
disposition to inline, provide a content_id, and reference it in HTML as <img src="cid:your-content-id">.
Pair this reference with deliverability guides and language quickstarts for production-ready integrations.