Email

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.

ProviderHostNotes
SendGridsmtp.sendgrid.net:587Username is the literal word apikey; password is an API key with Mail Send permission.
Mailgunsmtp.mailgun.org:587Credentials under Sending → Domain settings → SMTP. EU accounts use smtp.eu.mailgun.org.
Postmarksmtp.postmarkapp.com:587Server API token as both username and password.
Amazon SESemail-smtp.<region>.amazonaws.com:587SMTP credentials are not your AWS keys — generate them under SES → SMTP settings.
Resendsmtp.resend.com:465Username resend, password your API key.
Anything elseyour hostPort 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.

RecordWhat it does
SPFA TXT record naming the servers allowed to send for your domain, e.g. v=spf1 include:sendgrid.net ~all.
DKIMYour provider's key, published at the selector they name. Signs each message so forwarding does not break authentication.
DMARC_dmarc.yourdomain.comv=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.

Import your old suppression list before your first campaign. Mailing everybody who already opted out at your previous provider is the fastest way to get a domain blocklisted, and it is entirely avoidable.

Getting addresses in

HowWhat to call
From your backendnb.users.upsert({ external_id, email }) — server key.
From an SDKnb.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 fileImport 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

MeteringOne email to one person is one send, exactly like one push to one device. Both come out of monthly_messages.
RateTen messages a second per credential. Shared-mailbox providers throttle, and a throttled mailbox also stops sending your password resets.
Click trackingNot yet. Push clicks are tracked; email links are sent as you wrote them, untouched.
OpensNot tracked, and not planned as a default — an open pixel is a tracking pixel.
← Message contentWebhooks →