Udviklere → Vejledninger

Modtag e-mail i din app

Supporthenvendelser, svar på notifikationer, dokumenter mailet til en bot: mail til en adresse på Deres domæne ankommer til Deres HTTPS-endpoint som én signeret JSON-POST med teksten, HTML'en og alle vedhæftede filer. Ingen postkasse at polle og ingen IMAP.

Det skal De bruge

  • Et domæne registreret hos NameOcean: videresendelse og mail til webhook er gratis for disse.
  • Et HTTPS-endpoint på en offentlig adresse, der svarer inden for 20 sekunder.
  • nameocean-CLI'en eller en API-nøgle med email:write.

1. Slå videresendelse til for domænet

nameocean
$ nameocean email forwards on example.com

Dette peger domænets MX-record mod NameOceans mailvideresendere. Hvis domænet allerede har MX-records til postkasser et andet sted, stopper kommandoen og viser dem: al mail til domænet ville flytte hertil. Tilføj kun --replace-mx, når det er det, De ønsker.

2. Anmod om mail til webhook

Afsendelse af mail til en URL åbnes pr. konto efter en kort gennemgang for at holde spam-relæer ude. På domænets side under Dashboard → E-mailvideresendelse kan De anmode om det med en linje om, hvad De vil bruge det til. Indtil da svarer API'et 403 not_approved.

3. Send en adresse til Deres endpoint

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"}'

Svaret indeholder signeringshemmeligheden (whsec_…); gem den i Deres apps indstillinger. localpart * sender alle adresser på domænet, der ikke har deres eget alias. Et domæne kan have op til tre af disse webhooks.

4. Modtag den

Verificér signaturen over den rå body, og læs derefter JSON'en. En lille Flask-modtager:

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

Hvad der ankommer

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 forbliver den samme, når en mail sendes igen, så brug den til at springe dubletter over. in_reply_to og references fortæller Dem, hvilken af Deres egne mails nogen har svaret på.

Når Deres endpoint er nede

  • Et 2xx-svar betyder leveret. En 408, 429, 5xx, en timeout (20 sekunder) eller ingen forbindelse forsøges igen i 6 timer.
  • Alle andre 4xx er endelige: mailen sendes ikke igen af sig selv.
  • Mail, der ikke kunne sendes, gemmes i 30 dage. Find den med nameocean email forwards log example.com (eller GET /email/forwarding/example.com/messages) og frigiv den: den sendes én gang til med samme id.
  • Op til 500 mails om dagen pr. domæne går til webhooks; mail ud over det tilbageholdes på samme måde.