Email is a channel like web push or APNs, with one difference that shapes everything else: it is addressed to a person, not to a device. A user with an address is reachable whether or not they ever installed your app — which is most of a list migrated from another platform.
It sends through your mail server. Notibase does not resell an inbox: you connect the provider you already pay, the From address stays on your domain, and the sending reputation you build belongs to you rather than to a pool shared with strangers.
Connect a mail server
Console → Settings → Email → Provider. Presets fill in the host, port and username convention for SendGrid, Mailgun, Postmark, Amazon SES, Resend, Google Workspace and Namecheap Private Email; anything else is plain SMTP.
| Provider | Host | Notes |
|---|---|---|
| SendGrid | smtp.sendgrid.net:587 | Username is the literal word apikey; password is an API key with Mail Send permission. |
| Mailgun | smtp.mailgun.org:587 | Credentials under Sending → Domain settings → SMTP. EU accounts use smtp.eu.mailgun.org. |
| Postmark | smtp.postmarkapp.com:587 | Server API token as both username and password. |
| Amazon SES | email-smtp.<region>.amazonaws.com:587 | SMTP credentials are not your AWS keys — generate them under SES → SMTP settings. |
| Resend | smtp.resend.com:465 | Username resend, password your API key. |
| Anything else | your host | Port 587 (STARTTLS) or 465 (implicit TLS). |
Saving connects, upgrades to TLS, authenticates and hangs up before
MAIL FROM — a save that succeeds is proof the settings work, and nothing is
emailed to anyone. Unencrypted SMTP is refused, as is a host that resolves to a private
address.
Senders
Settings → Email → Senders lists every address this app may send as, one of them the default, plus an optional reply-to. The list is an allow-list: a message naming an address that is not on it is refused, not quietly sent as somebody else. Without that, anybody holding a server key could send as your CEO through credentials you uploaded for a newsletter.
Authenticate your domain
This is the part that decides whether your mail arrives. Unauthenticated email does not bounce — it is delivered to spam, which is the failure nobody notices.
| Record | What it does |
|---|---|
| SPF | A TXT record naming the servers allowed to send for your domain, e.g. v=spf1 include:sendgrid.net ~all. |
| DKIM | Your provider's key, published at the selector they name. Signs each message so forwarding does not break authentication. |
| DMARC | _dmarc.yourdomain.com → v=DMARC1; p=none; rua=mailto:[email protected]. Start at p=none, read a fortnight of reports, then tighten. |
The console checks all three against live DNS, resolved from our server, so it reports what a receiver would see rather than what a dashboard promised. Where a selector cannot be guessed — Amazon SES mints one per identity — paste it into the DKIM selector box.
Send one
An email block on any send. On its own it is an email-only campaign; beside
a title it is one message on two channels.
await nb.messages.send({
audience: { segment_id: "..." },
content: {
email: {
subject: "Your order is on its way, {{first_name}}",
html: "<p>Hi {{first_name}}, it left the warehouse this morning.</p>",
// text is generated from the HTML when you omit it
transactional: false,
fromAddress: "[email protected]" // optional; must be one of your senders
}
}
});
Full field reference: Message content → Email.
Unsubscribe is not optional
Every non-transactional message carries a one-click unsubscribe link and the RFC 8058
headers Gmail and Yahoo expect from bulk senders, signed for that recipient and that app.
A message marked transactional carries none — a receipt has nothing to opt out
of — and the provider refuses to send anything else without one, rather
than letting you discover the requirement from a blocklist.
List-Unsubscribe: <https://api.notibase.com/e/a/…>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Pressing it suppresses that address for every later send from that app, including sends made through the API. You can also opt somebody out yourself:
// server key
await fetch("https://api.notibase.com/v1/unsubscribe", {
method: "POST",
headers: { authorization: `Bearer ${SERVER_KEY}`, "content-type": "application/json" },
body: JSON.stringify({ email: "[email protected]", reason: "user_request" })
});
// or by your own user id, which covers their devices and their address at once
// { external_id: "u_123" }
Bounces and suppressions
A 5xx that means the mailbox does not exist is permanent: the address is suppressed once and never retried, because writing to dead mailboxes is how a sending domain gets blocked. A 4xx is temporary and is retried. Settings → Email → Suppressions groups the list by how each address got there — bounced, unsubscribed, or added by you — with search, CSV export, and a paste box for a list you are bringing from another platform.
Getting addresses in
| How | What to call |
|---|---|
| From your backend | nb.users.upsert({ external_id, email }) — server key. |
| From an SDK | nb.identify("u_123", { attributes: { email: "[email protected]" } }). The email attribute is promoted to the address column, so the person becomes email-reachable. Turn on identity verification if clients set addresses. |
| From a file | Import a CSV with an email column. A push token is no longer required — a row with an address and no token imports as a person, and OneSignal's email subscriptions (device_type 11) are read as addresses. |
Reach, reputation and reporting
The Email page in the console opens with the audience: reachable, have an address, bounced or opted out, total. The composer shows the same number for the audience you pick, with the suppression list already subtracted — the number on screen before you send is the number that gets written to.
Settings → Email → Reputation shows bounce and unsubscribe rates over 24 hours, 7 days and 30 days. Keep bounces under 2% and opt-outs under about 0.5%. Spam complaints are deliberately absent: seeing them requires a feedback loop with each mailbox provider, which belongs to whoever owns the sending IP — your provider, not us. A 0% we cannot measure would be worse than a gap.
Delivery events, webhooks and the per-message report cover
email like any other channel. Email events carry "channel": "email", a null
device_id — there is no device — and the recipient's address, so a
bounce can be synced back into your own system.
Limits and plan
| Metering | One email to one person is one send, exactly like one push to one device. Both come out of monthly_messages. |
| Rate | Ten messages a second per credential. Shared-mailbox providers throttle, and a throttled mailbox also stops sending your password resets. |
| Click tracking | Not yet. Push clicks are tracked; email links are sent as you wrote them, untouched. |
| Opens | Not tracked, and not planned as a default — an open pixel is a tracking pixel. |