Put key facts in the body
Amount, due date and invoice number in the email itself make it useful even before the PDF is opened.
Attach the PDF, pass the order details as template variables, and send exactly once — even when your billing job retries. Every message keeps an id, an event history and its attachment list for later lookups.
await fetch("https://sendix.dev/api/v1/emails", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.SENDIX_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": "invoice-" + invoice.number,
},
body: JSON.stringify({
from: "Acme Billing <[email protected]>",
to: [customer.email],
reply_to: "[email protected]",
template_id: INVOICE_TEMPLATE_ID,
template_data: { number: invoice.number, total: invoice.total },
attachments: [{
filename: "invoice-" + invoice.number + ".pdf",
content: pdf.toString("base64"),
contentType: "application/pdf",
}],
}),
});POST /v1/emails with the PDF in attachments (base64 content, filename and contentType; up to 20 attachments per message), the invoice fields in template_data and an Idempotency-Key such as the invoice number. Store the returned email id with the invoice so finance or support can check GET /v1/emails/{id}/events and GET /v1/emails/{id}/attachments later.
What your code does, what Sendix does, and where to look when something goes wrong.
Render the PDF in your billing system and base64-encode it for the attachments array.
Use the invoice or order number as the Idempotency-Key, so retries never email a customer twice.
Save the id returned with 202 Accepted next to the invoice record for support and audit lookups.
On email.bounced or email.failed, alert your billing team or fall back to another contact on the account.
Habits that protect deliverability and your users, whichever provider you use.
Amount, due date and invoice number in the email itself make it useful even before the PDF is opened.
Set reply_to to a monitored inbox, or receive replies through Sendix inbound and route them to your helpdesk.
A consistent billing@ address helps customers recognise and filter financial mail.
Compress PDFs and avoid unnecessary files; smaller messages are faster to process and less likely to be rejected.
E-commerce and billing tools that only speak SMTP can use smtp.sendix.dev:587; MIME attachments pass through.
Don’t add promotions to invoices; it blurs the transactional nature of the message.
Sendix signs each webhook with X-Sendix-Signature and keeps the same events on the message at GET /v1/emails/{id}/events.
| Event | What to do with it |
|---|---|
| email.sent | What to do with itQueued for delivery. |
| email.delivered | What to do with itAccepted by the customer’s mail server. |
| email.bounced | What to do with itPermanent failure — update the billing contact. |
| email.failed | What to do with itSendix could not deliver the message. |
| email.complained | What to do with itMarked as spam by the recipient. |
Short answers to the questions teams ask while wiring this up.
Yes. The API accepts up to 20 attachments per message, each with a filename, base64 content and an optional contentType. Over SMTP, standard MIME attachments are passed through.
Send the invoice number as the Idempotency-Key. A repeated request with the same key returns the original email id instead of creating a new message.
To the reply_to address you set. If you enable receiving on a domain, replies can also arrive in Sendix as parsed messages and trigger an email.received webhook.
Yes. With the stored email id, GET /v1/emails/{id} returns the message, /events its delivery history and /attachments the files that were sent.
The free plan includes 1,000 emails per month. Paid plans change volume and limits, not your API calls or SMTP settings.
1,000 emails free every month. No credit card required. Upgrade only when you outgrow the free tier — and we will let you know when that time comes.
Managed SaaS platform · Native SMTP engine · SOC 2 in progress