Send with attachments
Both transactional send endpoints accept an attachments[] array —
POST /public/email/send and POST /public/email/send-template. Each
attachment carries the file bytes inline as base64; we build the
multipart/mixed MIME structure for you, DKIM-sign it with your
verified sender domain, and ship it to the recipient through the same
self-hosted pipeline as plain-body emails.
Attachment object
Each entry in attachments[] is shaped like this:
{
"filename": "invoice-2026-04.pdf",
"content_type": "application/pdf",
"content_base64": "<base64-encoded file bytes>",
"content_id": "logo-header",
"inline": false
}| Field | Type | Required | Meaning |
|---|---|---|---|
filename | string | yes | Displayed by the recipient’s mail client. Directory separators + control chars are stripped automatically. Max 256 chars. |
content_type | string | optional | MIME type (e.g. application/pdf). When omitted, we infer from the filename extension and fall back to application/octet-stream. Max 256 chars. |
content_base64 | string | yes | Standard base64 encoding of the file bytes. Not URL-safe base64 — use the standard alphabet. |
content_id | string | optional | Sets Content-ID so HTML can reference the attachment as <img src="cid:logo-header">. Pair with inline: true. |
inline | boolean | optional | When true, sets Content-Disposition: inline (image renders in the body). When false (default), sets attachment (file appears in the recipient’s attachments list). |
Limits
| Cap | Value | What happens when exceeded |
|---|---|---|
| Files per message | 20 | Returns 400 INVALID_ATTACHMENT with "max 20 attachments per message" |
| Total decoded bytes | 10 MiB | Returns 400 INVALID_ATTACHMENT with the bytes-cap message. Sum runs across all attachments — a single 10.1 MiB PDF is rejected just like 11 × 1 MiB files. |
| Filename length | 256 chars | Rejected at validation. |
| Content-Type length | 256 chars | Rejected at validation. |
Blocked file types
Executable + script extensions are refused at the API layer because recipient mail providers (Gmail, Outlook, corporate gateways) block them outright — sending one would cost a wallet deduction for a guaranteed bounce. Blocked extensions:
.exe .bat .cmd .com .scr .msi .vbs .vbe .js .jse
.wsf .wsh .ps1 .dll .jar .app .sh .pl .py .lnk
Workaround: bundle them inside a .zip. ZIPs are allowed.
Example — single PDF
ATT=$(base64 -i invoice.pdf | tr -d '\n')
curl https://apis.splashifypro.com/api/v1/public/email/send \
-H "Authorization: Basic YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"to\": \"customer@example.com\",
\"subject\": \"Invoice for March\",
\"html\": \"<p>Hi! Your invoice for March is attached.</p>\",
\"from_name\": \"Acme Store\",
\"from_email\": \"billing@your-domain.com\",
\"attachments\": [
{
\"filename\": \"invoice-march-2026.pdf\",
\"content_type\": \"application/pdf\",
\"content_base64\": \"$ATT\"
}
]
}"Example — Node.js (multiple files)
import { readFileSync } from 'node:fs'
const toAtt = (path, contentType) => ({
filename: path.split('/').pop(),
content_type: contentType,
content_base64: readFileSync(path).toString('base64'),
})
const r = await fetch('https://apis.splashifypro.com/api/v1/public/email/send', {
method: 'POST',
headers: {
'Authorization': `Basic ${process.env.SPLASHIFY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
to: 'customer@example.com',
subject: 'Your March documents',
html: '<p>Attached: invoice + receipt + signed contract.</p>',
from_name: 'Acme Store',
from_email: 'billing@your-domain.com',
attachments: [
toAtt('./invoice.pdf', 'application/pdf'),
toAtt('./receipt.pdf', 'application/pdf'),
toAtt('./contract.pdf', 'application/pdf'),
],
}),
})
console.log(await r.json())Example — Python
import base64, requests, os
def att(path, ct):
with open(path, 'rb') as f:
return {
'filename': os.path.basename(path),
'content_type': ct,
'content_base64': base64.b64encode(f.read()).decode(),
}
r = requests.post(
'https://apis.splashifypro.com/api/v1/public/email/send',
headers={'Authorization': f"Basic {os.environ['SPLASHIFY_API_KEY']}"},
json={
'to': 'customer@example.com',
'subject': 'Attached photo',
'html': "<p>Here's the photo from your visit.</p>",
'from_name': 'Acme Store',
'from_email': 'support@your-domain.com',
'attachments': [att('./photo.jpg', 'image/jpeg')],
},
)
print(r.json())Example — Inline image (CID reference)
When you want the image to render inside the email body instead
of as a separate downloadable file, use inline: true + content_id,
then reference it from your HTML with cid::
{
"to": "customer@example.com",
"subject": "Today's newsletter",
"html": "<p>Welcome!</p><img src=\"cid:hero-banner\" />",
"from_name": "Acme Store",
"from_email": "newsletter@your-domain.com",
"attachments": [
{
"filename": "banner.png",
"content_type": "image/png",
"content_base64": "iVBORw0KGgo…",
"content_id": "hero-banner",
"inline": true
}
]
}Most modern mail clients (Gmail web + mobile, Outlook, Apple Mail) render inline images correctly. A few hardened corporate gateways strip them — the file falls back to a regular attachment in those.
Using attachments with templates
The same attachments[] field is accepted on
POST /public/email/send-template. The files are attached to the
rendered template output exactly as if you’d inlined the HTML on
/send:
{
"to": "customer@example.com",
"template_id": "0190ed42-1234-7c8e-9f0a-abcdef012345",
"variables": { "first_name": "Alice", "invoice_no": "INV-1042" },
"from_email": "billing@your-domain.com",
"attachments": [
{
"filename": "invoice-1042.pdf",
"content_type": "application/pdf",
"content_base64": "JVBERi0xLjcKJeLjz9MK…"
}
]
}Errors
| Status | Code | Reason |
|---|---|---|
| 400 | INVALID_ATTACHMENT | Too many files, total size exceeded, blocked extension, invalid base64, or empty content |
| 400 | — | from_email domain '<x>' is not verified. (same as plain send) |
| 401 | — | Missing / invalid API key |
| 402 | — | email_marketing not enabled on your plan |
| 429 | — | Per-plan rate limit; check Retry-After header |
Pricing
Attachments do not incur a per-byte charge. You’re billed at the per-recipient transactional rate (₹0.05/email beyond the daily-100 free tier + reseller markup if any), regardless of attachment size. The only practical cost is the 10 MiB total cap which limits how big each individual message can be.
Best practices
- Compress where you can. A PDF with images compressed to 200 dpi vs 600 dpi can be 5× smaller and still look perfect at on-screen resolution. Smaller messages deliver faster + use less of your 10 MiB budget.
- Use links for files > 5 MiB. Recipient mail providers throttle large messages and some flag them as suspicious. For anything bigger, host on object storage and put a download link in the body.
- Set
content_typeexplicitly when you can — saves us a filename-extension guess. The mail client’s “open with” picker uses this header. - Prefer real filenames. Generic
attachment.pdfis allowed but hurts deliverability slightly (Gmail’s spam filter weights template-shaped filenames).invoice-march-2026.pdfis better.
See also
- Send Email — the base transactional endpoint.
- Send Template Email — same endpoint with a saved template + variables.
- Authentication — how the
sk_live_…key works.