Frequently asked questions

The questions we are actually asked — by developers integrating the API, and by teams who have to account for a supplier in writing. The answers describe the platform as it behaves, including where that does not flatter us.

36 questions  ·  Updated October 30, 2026

Setup

Sending and setup

Can I send over SMTP, or is it API only?

Both, and they are the same path. The REST endpoint takes JSON; the SMTP relay authenticates with an API key and then submits through the same code, so everything decided by the key — the sending identity, the transport policy, the unsubscribe behaviour — applies identically whichever you use. There is no SMTP-only configuration to keep in step.

What are the SMTP settings?

Hostmail.zedmail.com
Port465 (implicit TLS) or 2587 (STARTTLS)
Usernameyour API key
Passwordthe same API key

We do not use port 25. If your host blocks outbound 25, that is not a problem to solve before you can send — one customer spent a month waiting for an unblock they never needed. Use 465 or 2587.

What DNS records do I publish?

Two CNAMEs for DKIM and one SPF include, added once per sending domain. The CNAMEs are the same targets for every customer, so a key rotation on our side never asks you to touch DNS again.

We will tell you the exact records when you add the domain, and check them with you afterwards rather than leaving you to interpret a propagation delay.

Can I send from a subdomain instead of our main domain?

Yes, and for application mail it is usually the better choice. A subdomain is added exactly like a domain, and DKIM signs with that subdomain, so DMARC passes on DKIM alignment and your organisational domain can keep a strict policy of its own.

Can one account hold several sending domains and keys?

Yes, with no fixed ceiling — one customer runs nine domains on a single account. Agencies and multi-tenant products usually want a key per client or per environment, which also keeps each one’s configuration independent: transport policy and unsubscribe behaviour are properties of the key, not of the account.

Does every key have to be locked to one From address?

No. Binding a key to a single From address is an option, not a rule, and it is on by default because most people want a credential that can only ever send as one identity. Leave that field empty and the key may send as any address on a domain you have verified; anything else is refused rather than silently rewritten.

Is there a free allowance?

The first 200 messages each day are included at no charge and need no payment method. The allowance does not accumulate — a quiet day does not lend its remainder to a busy one — and it continues to apply once a card is on file, with only the volume above it billed. Current rates are on the homepage.

What happens if my retry logic sends the same message twice?

Nothing, provided you pass an idempotency_key of your own on the send — an order number, a job id, anything unique to that one message. An identical retry within 24 hours returns the first response again, with 200 and an Idempotent-Replay: true header rather than the usual 202, and no second message goes out.

The edges are deliberate. A retry while the first attempt is still running answers 409 — the only reply that cannot double-send. The same key with a different message is refused with 422, because quietly handing back the first message’s id would mean the second never sent and nobody was told. And a send we reject releases its key, so a bad address or an unverified domain is something you fix and retry with the same key rather than a dead end.

Without a key the behaviour is unchanged, so nothing about existing integrations breaks. The header Idempotency-Key works too, if that suits your HTTP client better.

Compliance

Deliverability and CASL

What are transactional and broadcast streams, and which should my key be on?

A key declares what it is for. Transactional means the recipient's own action caused the message — a receipt, a password reset, a shipping notice. Broadcast means you chose when it went out and it went to many people — a newsletter, an announcement, a campaign. You pick the stream when you create the key.

The stream lives on the key, not on the request. That is deliberate, and it is what makes it work over SMTP: our relay authenticates with your API key and submits through the same code as the REST endpoint, so a key-bound stream needs no custom header. Providers that put the stream in a request field had to add stream-specific SMTP credentials afterwards, because some SMTP clients cannot set custom headers at all.

Three things follow from the choice:

  • The unsubscribe footer. Broadcast always carries one; transactional never does. The stream decides this rather than inheriting it, so the footer setting on a key is only consulted when that key has no stream.
  • How wide an opt-out goes. An unsubscribe from broadcast silences broadcast and leaves transactional alone — which is the whole point: declining your newsletter should not stop someone's own password resets. On a transactional key you can narrow it further still, to that one key.
  • Retention. Each stream can keep message data for a different length of time. See how long we keep message content.

Bounces and complaints stay account-wide on both streams, on purpose. A dead mailbox is dead whichever stream retries it, and a spam complaint is a statement about you and that recipient rather than about one stream. Customers share outbound addresses, so an address that keeps being retried on the other stream spends everyone's reputation and not only yours.

Which one? If the recipient's action caused the message, transactional. If you decided the timing, broadcast. CASL's unsubscribe duty attaches to commercial electronic messages and a receipt is not one, which is precisely why the two are treated differently. Keys created before streams existed carry no stream and behave exactly as they always did — nothing was rewritten underneath them.

Can I put the unsubscribe link in my own wording, where I want it?

Yes. Put {{unsubscribe_url}} anywhere in your HTML or text body and we replace it with that recipient's own unsubscribe URL:

<a href="{{unsubscribe_url}}">Stop receiving these</a>

It works in both parts of the message, escaped correctly for each, and the braces may carry spaces. The substitution happens when the message is sent rather than when the API accepts it, because the token identifies one recipient and does not exist before then.

Using the tag counts as your opt-out, so our footer is not bolted on underneath it — including when your wording is in a language our detection would not recognise.

Why this rather than linking your own handler. The wording and the placement are what most senders actually want to control; the plumbing is not. A link to your own endpoint takes that recipient outside our suppression list, outside the one-click unsubscribe endpoint Gmail and Yahoo require of bulk senders, and outside the short survey we show on the way out. The tag gives you the wording and keeps all three.

We have our own unsubscribe system. Can I turn yours off?

Yes, per key or for the whole account. You may also find it already stands aside: before adding anything we scan both the HTML and plain-text parts of your message for an existing opt-out, in several languages, and suppress our own footer when you have one. The footer was never meant to land underneath yours.

If I use my own mechanism, do the List-Unsubscribe headers change?

On broadcast mail, no — they stay on every message, because Gmail and Yahoo require one-click of bulk senders and removing them would cost you placement rather than protect your flow.

On transactional mail they are not sent at all, and that is deliberate. A password reset is not bulk mail, so the requirement never reached it — but the header still drew the mailbox provider’s own unsubscribe button, and that button takes no confirmation. A recipient tapping it on an invoice stopped receiving every invoice from you, with nothing on screen telling them that is what they had just done. Turn on key-scoped unsubscribe for a transactional key and the headers come back, narrowed to that one key — a consequence small enough to be worth offering. Either way the {{unsubscribe_url}} merge tag works on both streams, and it lands on a page that says what it will do before it does it.

The consequence is worth planning for. A recipient who uses the mailbox provider’s own unsubscribe button is recorded as unsubscribed with us, and your system will not know unless you consume the unsubscribed webhook. Consume it and the two stay in step, with your own mechanism remaining the one your users see.

Separately, every message carries a List-Help header pointing at a page written for your recipients rather than for you. It says that you sent the message and we only carried it, that only you hold the record of how their address reached you, and what they can do on the stream the message came from. It names your sending domain and nothing about the recipient.

What gets suppressed automatically?

A recipient who unsubscribes, a mailbox that hard-bounces, and an address that reports a message as spam. Suppression is enforced at send time, so a later attempt to that address is refused rather than delivered and regretted.

Reputation refusals and temporary failures are deliberately not treated as dead mailboxes: a receiver throttling us, or an authentication complaint, says nothing about whether the address exists.

How wide is an opt-out?

An unsubscribe can be scoped to one API key rather than the whole account, which matters if you send genuinely separate kinds of mail — someone declining your newsletter should not thereby decline their own password resets. Spam complaints and hard bounces are account-wide and are not narrowable: a complaint is a statement about you and that recipient, and a dead mailbox is dead for every key you own.

Will a full mailbox drop a subscriber from my list?

Not through us. Only hard bounces raise the bounced webhook; mailbox-full, greylisting and reputation deferrals update the message record without firing an event. List managers tend to treat any bounce event as terminal, and that behaviour was quietly removing hundreds of valid contacts from customer lists.

Integration

Webhooks and getting data back

What events can I receive?

delivered, bounced, blocked, complained, unsubscribed, opened and clicked. Every payload carries event, a message identifier and a timestamp; events with detail add a data object, and events without one omit it, so treat it as optional.

unsubscribed is the exception worth reading twice: it has no message identifier, because an opt-out is an action against an address rather than a bounce of one particular message, and the link stays valid long after that message has left your retention window. Read the address from data.

Can a webhook endpoint be tied to a single API key?

Yes. An endpoint can be bound to one key, so a staging environment’s events reach a staging receiver and production reaches production, with no demultiplexing in between. Leave an endpoint unbound and it receives everything on the account, which is how endpoints behaved before the option existed.

A URL supplied with each individual message is not offered, and the reason is not oversight: it would mean posting to whatever endpoint a request named, with retry state for addresses that may never have existed.

How do I tell which key an event came from?

Every event we can attribute to a key carries the key’s own identifier. It is not the secret and not derived from it, it survives a key rotation, and it is safe to log and store — which makes it a sound routing value if you would rather keep one shared endpoint than several bound ones.

Can I attach my own identifiers to a message and get them back?

Yes, two ways, and the choice turns on one question: does something at the receiving end need to read your identifier?

If not, use tags (tags): up to ten per message, fifty characters each, stored with the message and returned on the delivery and failure events. They never leave our side, so the recipient never sees them. Two limits to design around: tags are trimmed to those bounds rather than rejected, so a long composite identifier can arrive shortened; and because unsubscribed carries no message, it carries no tags either — use the key identifier if you need to attribute an opt-out.

If so, use custom headers (headers): they go on the message, where a system at the receiving end can read them, and come back in every webhook event about it. One field does both jobs; elsewhere you generally need a header for the message and a separate metadata field to get a value returned.

"headers": { "X-Survey-ID": "survey-8842" }

Up to ten headers, 64 bytes per name, 200 bytes per value, 2 KB in total. Unlike tags, a bad header fails the send with a 422 naming it — nothing is trimmed or escaped, so you will never have a header you think you set and didn't. Headers we set ourselves (From, Subject, Message-ID, Content-*, List-* and the rest) are refused rather than overridden.

Two judgement calls. A header travels with the message, so it is visible to the recipient, their mail provider and anyone the email is forwarded to — keep the value opaque. And a custom header is not covered by the DKIM signature, which is fine for a correlation id but should not be treated as proof of origin.

Are webhook deliveries signed and retried?

Each endpoint has its own secret, shown once when you create it, and deliveries are signed with it so your receiver can reject anything it cannot verify. Failed deliveries are retried on a backoff; an endpoint you disable stops receiving rather than accumulating a backlog.

Residency

Where your data lives

Where is message data stored?

In Canada. Sending infrastructure and the database are in the Beauharnois, Québec region, and encrypted off-site backups are held in Québec as well. The service is administered from Ottawa, Ontario.

If you or your client falls under Québec’s Law 25, note that administration from outside Québec is a factor in your own privacy impact assessment. We will give you what you need for it rather than leave you to infer it.

Who operates Zedmail?

Ozonagram Ltd, a Canadian federal corporation. There is no parent company, no outside investor with control, and no office or staff outside Canada.

Is our data exposed to the US CLOUD Act?

Our reading is no, and the reasoning is about corporate structure rather than reassurance. The CLOUD Act reaches providers subject to US jurisdiction — US companies and the subsidiaries of US groups. It runs down from a US parent; it does not run up from a foreign one.

Our hosting is provided by a French group through its Canadian company, and that group’s US business is a separately governed subsidiary. The group states in its annual regulated filing that only the US subsidiary falls under those rules, because non-US activity is segregated from it, and its published analysis says the same of the Canadian company specifically: out of scope, with mutual legal assistance the route an American authority would have to take.

Who are your sub-processors?

Five, and only one of them can read your email: hosting. Recipient addresses, message content and delivery logs are stored in Canada, in OVHcloud data centres in Québec, with OVH Hébergement Inc. No sub-processor is permitted to store or access that information outside Canada.

A second copy of the encrypted backups is held by CanHost Inc. in Kelowna, British Columbia, so that a failure at one provider cannot take both the service and the means to rebuild it. That copy is ciphertext: CanHost is never given the decryption key, which is held offline and has never been placed on any server. Added 1 November 2026.

The other three receive none of it. Paddle (United Kingdom) is our merchant of record and receives account and billing data only — never recipient addresses, message content or delivery logs. Bunny.net and Hostinger publish the authoritative DNS for our own domains; DNS records are public by definition and carry no personal data.

There is no third-party sending service, relay or spam-filtering service in the path. The mail servers are our own software on our own machines, and analytics is self-hosted. The authoritative list is Annex C of our Data Processing Agreement, which governs if this summary and the DPA ever disagree.

Does anyone outside Canada have access to your systems?

No — including contractors.

Will you sign a data processing agreement?

There is one published at zedmail.com/dpa.php. It forms part of the terms and is accepted with them without a signature, and we will execute a signed copy if your process requires one on file.

How long do you keep message content?

You choose: anywhere from 7 to 365 days, set on the account and, if you want, set separately for each stream — a short window on broadcast and a longer one on the receipts you may have to produce later. When the window passes, the whole record goes together: recipient, subject, body and delivery status.

The floor is seven days rather than one for a reason worth knowing: below that, a bounce can arrive after the message record it belongs to is already gone, and the address never gets suppressed.

Three exceptions, because a complete answer is more useful than a short one:

  • Encrypted backups are not edited when live data is deleted, so a deleted record persists in a backup until that backup expires — no more than 90 days.
  • Messages we refuse at validation are logged separately, with the recipient address and the error code but no content, for 30 days, so “why are my sends failing” is answerable.
  • Suppression records persist by design. The alternative to remembering an opt-out is mailing that person again.

Is mail encrypted in transit? Can we require it?

Every message is encrypted in transit whenever the receiving server offers it. You can also require it per key, in which case a message to a server that cannot offer verified encryption is not sent rather than sent in the clear, and we tell you which recipients were affected.

For the major consumer providers it is enforced regardless, because they publish policies saying their servers should never accept unencrypted mail, and we hold them to that.

How quickly would you tell us about a security breach?

Within 72 hours of becoming aware, committed in the terms: what we know and what we are doing about it. Deciding whether regulators or individuals must be notified is yours, and our job is to give you what you need to decide it.

Service

Reliability and commitments

What uptime do you commit to, and is it in writing?

99.5% monthly on the submission endpoints, measured across five-minute intervals, with service credits if it is missed and stated exclusions. It is section 6 of the terms rather than something offered on request, and you can hold it against externally operated monitoring at status.zedmail.com.

How would we hear about an outage?

Affected accounts are emailed and the status page is updated. Separately and automatically: if sending is ever held on your account — for a bounce or complaint rate above threshold, say — you are emailed at once with the reason, rather than discovering it from failed API calls.

What notice would we get if Zedmail were discontinued?

At least 90 days in writing, to your billing contact and in the dashboard. It is in section 7 of the terms, and it commits to more than the notice period: the service runs normally throughout, including the uptime commitment; nothing is billed for any period after it stops; unused prepaid credit is refunded; and you can export your sending data, delivery logs and suppression lists throughout.

That last item is worth checking against any vendor you evaluate. Your compliance obligations outlive the contract, and you cannot honour opt-outs you were not able to take with you.

Are there sending limits? Will transactional mail keep flowing on a busy day?

There are limits, but they are per-account settings rather than plan tiers: a daily cap and a per-minute rate, both raised on request. A message is refused if you cross the cap, so the right move at onboarding is to set it comfortably above your expected peak rather than at it — tell us the busiest day you can imagine and we will set it above that.

Assurance

Security posture

What security controls do you have?

  • Encryption at rest on the database volume, with unattended boot unlock and a documented inventory of every key that can open it.
  • Encrypted off-site backups whose decryption key is held offline, verified nightly and restore-tested on a schedule — a backup nobody has restored is a hope, not a control.
  • Transport encryption that can be made mandatory per key, failing a send rather than downgrading it.
  • Scoped API keys, revocable and rotatable, with the secret shown once and stored only as a hash.
  • Administrative actions recorded in an audit log.
  • A published data processing agreement rather than one produced on request.

A question that is not here?

Write to hello@zedmail.com. If the answer belongs on this page it will be added to it — most of the questions above arrived exactly that way.