Ontwikkelaars → Handleidingen

E-mail ontvangen in uw app

Supporttickets, antwoorden op meldingen, documenten die naar een bot worden gemaild: mail aan een adres op uw domein komt als één ondertekende JSON-POST binnen op uw HTTPS-endpoint, met de tekst, de HTML en alle bijlagen. Geen mailbox om te pollen en geen IMAP.

Wat u nodig hebt

  • Een domein dat bij NameOcean is geregistreerd: doorsturen en mail naar webhook zijn daarvoor gratis.
  • Een HTTPS-endpoint op een openbaar adres dat binnen 20 seconden antwoordt.
  • De nameocean CLI, of een API-sleutel met email:write.

1. Doorsturen inschakelen voor het domein

nameocean
$ nameocean email forwards on example.com

Hiermee verwijst het MX-record van het domein naar de mailforwarders van NameOcean. Heeft het domein al MX-records, voor mailboxen elders, dan stopt het commando en toont het deze: alle mail voor het domein zou dan hierheen gaan. Voeg --replace-mx alleen toe als u dat echt wilt.

2. Mail naar webhook aanvragen

Mail naar een URL posten wordt per account vrijgegeven na een korte beoordeling, om spamrelays te weren. Vraag het aan op de pagina van het domein onder Dashboard → E-mail doorsturen, met een korte toelichting op waarvoor u het gebruikt. Tot die tijd antwoordt de API met 403 not_approved.

3. Een adres naar uw endpoint sturen

nameocean
$ nameocean email inbound add example.com support https://app.example.com/hooks/mail
curl
$ curl -X POST https://nameocean.net/api/v1/email/forwarding/example.com/webhooks \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d '{"localpart": "support", "url": "https://app.example.com/hooks/mail"}'

Het antwoord bevat het ondertekeningsgeheim (whsec_…); bewaar dit in de instellingen van uw app. Met localpart * wordt elk adres van het domein doorgestuurd dat geen eigen alias heeft. Een domein kan maximaal drie van deze webhooks hebben.

4. Ontvangen

Verifieer de handtekening over de onbewerkte body en lees daarna de JSON. Een kleine Flask-ontvanger:

app.py
import base64, hashlib, hmac, json, os, time

from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["NAMEOCEAN_WEBHOOK_SECRET"]  # whsec_...


def verified(header, body, tolerance=300):
    fields = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
    ts = int(fields.get("t", "0"))
    if abs(time.time() - ts) > tolerance:
        return False
    expected = hmac.new(SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, fields.get("v1", ""))


@app.post("/hooks/mail")
def mail():
    body = request.get_data()
    if not verified(request.headers.get("X-NameOcean-Signature", ""), body):
        abort(401)
    mail = json.loads(body)
    print(mail["envelope"]["from"], "→", mail["envelope"]["to"], mail["subject"])
    for a in mail["attachments"]:
        data = base64.b64decode(a["content_base64"])
        print("  attachment", a["filename"], a["content_type"], len(data), "bytes")
    return "", 204  # any 2xx: delivered

Wat er binnenkomt

POST https://app.example.com/hooks/mail
X-NameOcean-Event: email.received
X-NameOcean-Delivery: 6f1c2a4e-8b3d-4f5a-9c7e-1d2b3a4c5e6f
X-NameOcean-Signature: t=1794300000,v1=5f2b…

{
  "id": "6f1c2a4e-8b3d-4f5a-9c7e-1d2b3a4c5e6f",
  "event": "email.received",
  "received_at": "2026-11-11T09:30:12+00:00",
  "envelope": {"from": "alice@example.org", "to": "support@example.com"},
  "from": "Alice <alice@example.org>",
  "to": "support@example.com",
  "cc": null,
  "reply_to": null,
  "subject": "Order 1042",
  "date": "Wed, 11 Nov 2026 09:30:05 +0000",
  "message_id": "<…@example.org>",
  "in_reply_to": null,
  "references": null,
  "text": "Hi…",
  "html": "<p>Hi…</p>",
  "headers": [["From", "Alice <alice@example.org>"], …],
  "attachments": [{"filename": "invoice.pdf", "content_type": "application/pdf", "content_id": null,
                   "size": 48211, "content_base64": "JVBERi0…"}],
  "spam_score": 0.4,
  "size": 66120
}

id blijft gelijk wanneer een mail opnieuw wordt gepost, dus gebruik dit om duplicaten over te slaan. in_reply_to en references vertellen u op welke van uw eigen mails iemand heeft geantwoord.

Als uw endpoint niet bereikbaar is

  • Een 2xx-antwoord betekent afgeleverd. Bij een 408, 429, 5xx, een time-out (20 seconden) of geen verbinding wordt het 6 uur lang opnieuw geprobeerd.
  • Elke andere 4xx is definitief: de mail wordt niet automatisch opnieuw gepost.
  • Mail die niet kon worden gepost, wordt 30 dagen bewaard. Zoek deze op met nameocean email forwards log example.com (of GET /email/forwarding/example.com/messages) en geef hem vrij: hij wordt dan nogmaals gepost, met dezelfde id.
  • Per domein gaan maximaal 500 mails per dag naar webhooks; mail daarboven wordt op dezelfde manier vastgehouden.