Features
Message Tags
Label a send with your own name and value pairs. The label rides the message and comes back on every event, so logs and dashboard slice by campaign.
Your own labels on every message
An untagged sending log is one undifferentiated stream. A question like how Tuesday’s invoice run delivered gets answered by exporting it and grouping by hand.
A tag is a name and a value you pick: campaign and spring-sale, or tenant and acme. The pair is stored, carried with the message, and handed back untouched. What a tag means is yours to decide, and nothing on our side depends on the vocabulary you choose.
curl -X POST https://api.mailkube.com/mta/v1/emails \
-H "Authorization: Bearer mk_<key_id>_<secret>" \
-H "Content-Type: application/json" \
-H "User-Agent: acme-billing/1.4" \
-d '{
"from": "Acme <hello@yourdomain.com>",
"to": "customer@example.com",
"subject": "Your order has shipped",
"html": "<h1>On its way</h1><p>Track your order at...</p>",
"tags": [
{ "name": "campaign", "value": "spring-sale" },
{ "name": "tenant", "value": "acme" }
]
}'
Over SMTP the identical array travels in an X-Mailkube-Tags header:
swaks --server smtp.mailkube.com --port 587 -tls \
--auth --auth-user myapp01@yourdomain.com --auth-password "$SMTP_PASSWORD" \
--from hello@yourdomain.com \
--to customer@example.com \
--h-Subject "Your order has shipped" \
--add-header 'X-Mailkube-Tags: [{"name":"campaign","value":"spring-sale"},{"name":"tenant","value":"acme"}]' \
--body "On its way."
Single-quote that header. Unquoted, the shell takes the JSON apart before swaks ever sees it.
Where a tag turns up afterwards
The log entry keeps it. Narrowing your send history to one campaign, one customer or one release is a filter rather than an export. The dashboard groups volume by tag in its Tags Performance view, where you compare how each labelled slice actually delivered. Every email.* webhook echoes the tags back in its data block. A receiver can route on tenant or attribute a click without looking anything up on your side.
The webhook echo is why tagging happens at send time. The attribution arrives with the event.
What the validator enforces
| Rule | Detail |
|---|---|
| Character set | ASCII letters, digits, underscore and hyphen |
| Length | 16 characters for name, 32 for value |
| Name | Required, and unique within one send |
| Value | May be blank |
| Count | 20 tags per message |
Break any of those and the whole send fails rather than the tag being quietly dropped. That is a validation_error over REST or a 5.6.0 reply over SMTP, with the reason in the text. The SMTP header has one extra bound: it has to parse as JSON and stay under 16 KB.
Those limits are tight. A tag is a label you group by, not somewhere to park a payload.
Keep personal data out of the values
Tag values are stored in the clear, and they stay out of the aggregate metrics. Neither is a problem for the surfaces above, which read your own send history.
There is a contractual reason too. The Data Processing Addendum counts tags as personal data. Exhibit A lists “message tags supplied by the Customer as name and value pairs” among the categories mailkube processes on your behalf. Whatever you put in a tag is covered by the Addendum from the moment you send it. Section 6 then rules out erasing message metadata for one recipient on request. Those records are what the service relies on to protect its own security and sending reputation. A tag carrying a name or an address leaves on the Section 11 retention window with everything else. That window runs from 7 to 90 days by plan, and up to twelve months in the analytics copy.
Write tenant: 4f9c rather than a customer’s name, and never a recipient address.
Tags, topics and validation rules
Tags(opens in a new tab) has the validation rules and every surface a tag reaches. If you are labelling sends to decide who receives them, that is a topic(opens in a new tab) rather than a tag. Topics filter recipients who opted out; tags only describe.