Arawa Mail Arawa MailDocs

Outgoing Webhooks

Outgoing webhooks push incoming email into your own systems. Whenever an email arrives in one of your mailboxes, Arawa Mail sends an HTTP POST with the full email as JSON — including download links for any attachments — to every notify URL you configure.

Typical uses: feeding a helpdesk or CRM, triggering automations, or archiving mail in your own storage.

Add a Notify URL

  1. Open Settings → Outgoing webhooks in the admin dashboard.
  2. Click Add notify URL.
  3. Enter the URL that should receive the POST. It must be reachable from the internet over HTTPS.
  4. Optionally set a secret and a recipient filter (both explained below).
  5. Save. The webhook is active immediately.

You can add as many notify URLs as you need — each incoming email is delivered to every active URL whose filter matches.

Filtering Which Emails Notify a URL

Each notify URL has an optional filter — a list of entries the incoming email's recipient is matched against:

Entry form Example Matches
Full mailbox address [email protected] Only mail delivered to that exact mailbox
Bare domain acme.com Mail delivered to any mailbox under that domain

Rules:

  • An empty filter means the URL is notified for every incoming email in your workspace.
  • Entries are case-insensitive.
  • A URL is notified once per email when any of its entries matches.

Verifying Requests with a Secret

If you set a secret on a notify URL, Arawa Mail sends it with every request as a header:

X-Webhook-Secret: your-secret-value

Your endpoint should compare the header against the value you configured and reject requests that don't match. This prevents anyone who discovers your endpoint URL from feeding it forged emails.

The secret is stored encrypted and is never shown again in the dashboard after you save it — you can only replace or remove it.

Request Format

  • Method: POST
  • Content type: application/json
  • Headers: X-Webhook-Secret (only when a secret is set)

Payload

{
    "id": 481,
    "message_id": "[email protected]",
    "thread_id": 466,
    "recipient": "[email protected]",
    "from_name": "Jane Doe",
    "from_email": "[email protected]",
    "to_recipients": [{ "name": "Support", "email": "[email protected]" }],
    "cc_recipients": [],
    "subject": "Order #1042 arrived damaged",
    "text_body": "Hi team, the package arrived damaged...",
    "html_body": "<p>Hi team, the package arrived damaged...</p>",
    "snippet": "Hi team, the package arrived damaged...",
    "has_attachments": true,
    "received_at": "2026-07-16T09:24:11+03:00",
    "attachments": [
        {
            "filename": "damage-photo.jpg",
            "content_type": "image/jpeg",
            "size": 482113,
            "url": "https://…signed-download-url…"
        }
    ]
}

Field Reference

Field Type Description
id integer Arawa Mail's ID for the stored email.
message_id string | null The email's Message-ID header, without angle brackets.
thread_id integer ID of the conversation thread the email belongs to.
recipient string The mailbox address the email was delivered to. This is the address the filter matched.
from_name string | null Sender display name.
from_email string | null Sender address.
to_recipients array To header addresses as { name, email } objects.
cc_recipients array Cc header addresses as { name, email } objects.
subject string | null Email subject.
text_body string | null Plain-text body.
html_body string | null HTML body.
snippet string | null Short plain-text preview of the body.
has_attachments boolean Whether the email carried attachments.
received_at string | null When the email was received, ISO-8601.
attachments array Attachment descriptors — always present, empty when the email has none.

Attachments

Each entry in attachments:

Field Type Description
filename string | null Original file name.
content_type string | null MIME type.
size integer | null Size in bytes.
url string Signed download URL, valid for 24 hours.

Attachment contents are never embedded in the payload — download them from url. Because the link expires after 24 hours, fetch and store the file promptly if you need to keep it. In the rare case an attachment's file could not be stored when the email arrived, that attachment is omitted from the array (the email itself is still delivered).

Responses, Timeouts, and Retries

  • Your endpoint must respond within 15 seconds.
  • Any 2xx status counts as delivered. Keep processing fast — acknowledge first, do heavy work asynchronously.
  • Any other status, or a timeout, counts as a failure. Delivery is retried up to 3 attempts in total, waiting 30 seconds, 2 minutes, and 5 minutes between attempts. After the final failure the notification is dropped (the email itself is always kept in the mailbox).
  • Deliveries can occasionally arrive more than once — use id or message_id to deduplicate.

Example Receiver

A minimal Laravel route that verifies the secret and reads the payload:

Route::post('/webhooks/incoming-email', function (Request $request) {
    abort_unless(
        hash_equals(config('services.email.webhook_secret'), (string) $request->header('X-Webhook-Secret')),
        401
    );

    $email = $request->json()->all();

    Log::info('Incoming email', [
        'from' => $email['from_email'],
        'subject' => $email['subject'],
        'attachments' => count($email['attachments']),
    ]);

    return response()->noContent();
});

The same in Express:

app.post('/webhooks/incoming-email', express.json(), (req, res) => {
    if (req.get('X-Webhook-Secret') !== process.env.EMAIL_WEBHOOK_SECRET) {
        return res.sendStatus(401);
    }

    const email = req.body;
    console.log(`Incoming email from ${email.from_email}: ${email.subject}`);

    res.sendStatus(204);
});

Managing Notify URLs

From Settings → Outgoing webhooks you can:

  • Edit a URL, its filter, or its active state at any time.
  • Replace or remove the secret (leave the field blank while editing to keep the current one).
  • Disable a URL without deleting it — deliveries stop immediately and resume when re-enabled.
  • Delete a URL — deliveries stop immediately.