Skip to content

Receive email in your code

Point your domain's MX at Mektup and every email sent to it is stored in a real mailbox and handed to your code: as a signed JSON webhook when it lands, through REST endpoints for messages, threads and attachments, or over IMAP. Nothing is lost if your endpoint is down.

Updated

Three ways to get inbound mail

WayBest forHow
WebhookReacting at once: agents, tickets, order mailOne URL per mailbox, JSON, HMAC-SHA256 signed
REST APIReading history, threads and attachmentsGET /v1/messages, /v1/threads/:key, /v1/messages/:id/attachments/:n
IMAPExisting IMAP code, and peoplemail.usemektup.com:993, every folder

The webhook

When a message is stored, Mektup posts this to your URL with an X-Mektup-Signature: sha256=… header, an HMAC-SHA256 of the raw body with your webhook secret:

POST to your webhook
{
  "event": "message.received",
  "mailbox": "orders@yourcompany.com",
  "message": {
    "id": "3f6d…",
    "from": "customer@example.org",
    "to": "orders@yourcompany.com",
    "subject": "Order 1042: wrong size",
    "text": "Hi, I received a medium but ordered a large…",
    "receivedAt": "2026-10-23T09:14:02Z",
    "threadKey": "<CAF…@mail.gmail.com>"
  }
}

The text body is included up to 20,000 characters; fetch the HTML and attachments with GET /v1/messages/:id. Mail from senders you have blocked never fires the webhook.

Verify and handle it (Python, Flask)
import hashlib, hmac, json, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["MEKTUP_WEBHOOK_SECRET"].encode()

@app.post("/inbound")
def inbound():
    raw = request.get_data()  # the exact bytes Mektup signed
    expected = hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    got = request.headers.get("X-Mektup-Signature", "").removeprefix("sha256=")
    if not hmac.compare_digest(expected, got):
        abort(401)
    event = json.loads(raw)
    handle(event["mailbox"], event["message"])  # your code
    return "", 200

Read with the REST API

# unread threads in a mailbox, newest first
curl "https://api.usemektup.com/v1/messages?mailbox=orders@yourcompany.com&direction=inbound&limit=50" \
  -H "Authorization: Bearer $MEKTUP_API_KEY"

# the full message: text, html and the list of attachments
curl "https://api.usemektup.com/v1/messages/3f6d…" -H "Authorization: Bearer $MEKTUP_API_KEY"

# the first attachment, raw bytes
curl -o invoice.pdf "https://api.usemektup.com/v1/messages/3f6d…/attachments/0" \
  -H "Authorization: Bearer $MEKTUP_API_KEY"

Messages are grouped into threads from their Message-ID, In-Reply-To and References headers. Reading a message marks it read, like a mail client would; PATCH /v1/messages/:id marks it unread, flags it or moves it to a folder.

Compared with parse webhooks

SendGrid Inbound Parse, Postmark inbound, Mailgun routes and Resend inbound receive mail for your domain and post it to your endpoint. That is what you need when mail is only data for your code. Mektup also stores every message in a mailbox, which matters when:

  • you need to read a message again, or the whole conversation, after your code handled it;
  • a person has to see or answer the mail, in webmail or their own mail app;
  • the same address must also send, and replies should come back to it;
  • your endpoint was down and you want the mail anyway.

Side by side: SendGrid, Postmark, Mailgun, Resend.

Set it up

  1. Add the domain (or a subdomain such as in.yourcompany.com, so your normal mail stays where it is) and add the records Mektup returns.
  2. Create a mailbox for each address that should receive.
  3. Set the webhook URL per mailbox and keep the secret from the response.
  4. Verify the signature in your handler, answer within 8 seconds, then do the work.

Questions

What is an inbound email API?

A service that receives email for your domain and hands it to your software: as a webhook when mail arrives, through API calls to list and read messages, or both. With Mektup the mail is also stored in a real mailbox, so you can read it again later, and people can open it in a mail app.

How do I forward incoming email to a webhook?

Point your domain's MX record at mail.usemektup.com, create a mailbox (for example orders@) and set its webhook URL with PUT /v1/domains/:domain/mailboxes/:localPart/webhook. Every new message is posted to that URL as JSON with an HMAC signature.

What happens if my endpoint is down?

The message is already stored in the mailbox before the webhook fires, so nothing is lost. The webhook is one attempt with an 8-second timeout; to be sure you see everything, also list unread messages with GET /v1/messages on a schedule.

Can I read the mail over IMAP instead?

Yes. Every mailbox has IMAP on mail.usemektup.com:993 with its own password, with all folders. Most languages have an IMAP library, and people can use the same login in a mail app.

Does received mail cost anything?

No. Mektup's Starter limits count the recipients of mail you send. Received mail only uses storage: 15 GB per account.

Start today, or talk to us?

Starter is $20 a month. Agencies get a quote for every client domain on one account.