Webhook Payload

The payload of the webhook is the same as the response of the get_email_content endpoint. The only addition is a timestamp field, which can be used to prevent replay attacks if you’re using a signing_secret as your webhook_authentication_type. The timestamp is a string in ISO 8601 format.

Payload

plain_text
string | null

The plain text content of the email. Can be null if the email is only available in html

html
string | null

The html content of the email. Can be null if the email is only available in plain text

alternative_content
boolean

If true, html and plain_text are alternative representations of the same content

attachments
object[]
to_addresses
object[]
from_address
object[]
cc_addresses
object[]
bcc_addresses
object[]
reply_to_addresses
object[]
subject
string

The subject of the email

date
string

The date of the email in ISO 8601 format

id
string

The BotMailRoom ID of the email

timestamp
string

The timestamp of the webhook in ISO 8601 format

Configuring and Validating Webhooks

When creating or updating an inbox, you can specify a webhook_url and webhook_authentication_type. The webhook_authentication_type can be either signing_secret or bearer_token.

Signing Secret

Getting the Signing Secret

When you create an inbox and have webhook_authentication_type set to signing_secret, BotMailRoom will generate a signing secret and include it in the response.

You will only receive this particular signing secret once, so make sure to save it in a secure location.

If you need to regenerate the signing secret, you can do so by going to the inboxes page, clicking edit on the inbox you want to update, and then clicking the regenerate button next to the signing secret.

Regenerate Signing Secret

Using the Signing Secret

The webhook signing secret allows you to verify that an incoming request to your service is actually coming from BotMailRoom.

You can use the python client to verify the signature of the webhook:

from botmailroom import verify_webhook_signature

verify_webhook_signature(signature_header, payload, webhook_secret)

Alternatively, you can manually verify the signature, here’s how the process works:

  1. When BotMailRoom sends a webhook with the email payload, it creates a special signature by:

    • Taking the webhook payload (as raw bytes)
    • Using HMAC-SHA256 with your shared secret
    • Converting the result to a hexadecimal string
    • Including this signature in the X-Signature header
  2. When you receive the webhook, you need to:

    • Take the raw payload bytes
    • Generate the same signature using your signing secret
    • Compare signatures
    • To avoid replay attacks, you can also check the timestamp in the payload and ensure it’s within a reasonable time window

If the signatures match, you know:

  • The request definitely came from BotMailRoom
  • The data wasn’t modified in transit

Here’s an example of how to verify the signature in Python:

import hashlib
import hmac
from datetime import datetime, timedelta

def verify_webhook_signature(
    signature_header: str, payload_bytes: bytes, webhook_secret: str
) -> bool:
    hash_object = hmac.new(
        webhook_secret.encode("utf-8"),
        msg=payload_bytes,
        digestmod=hashlib.sha256,
    )

    expected_signature = hash_object.hexdigest()
    signatures_match = hmac.compare_digest(expected_signature, signature_header)
    if not signatures_match:
        return False

    # Optional: check timestamp within some window
    payload = json.loads(payload_bytes)
    timestamp = datetime.fromisoformat(payload["timestamp"])
    age = datetime.now() - timestamp
    if age < timedelta(minutes=-1):
        # timestamp is in the future
        return False
    if age > timedelta(minutes=10):
        # timestamp is too old
        return False

    return True

Bearer Token

Getting the Bearer Token

When you create an inbox with webhook_authentication_type set to bearer_token, you’ll need to provide your own bearer token. This token should be a secure, random string that you generate and keep private. You can provide this token in the webhook_secret field when creating or updating your inbox.

Using the Bearer Token

If you’re already validating requests to your service with bearer tokens, you can use that same strategy here instead of generating a signing secret.

  1. BotMailRoom will send the webhook with:

    • The email payload in the request body
    • An Authorization header with format: Bearer your-token-here
  2. When you receive the webhook, you should:

    • Extract the bearer token from the Authorization header
    • Compare it with your stored token
    • Only process the webhook if the tokens match
def verify_bearer_token(auth_header: str, expected_token: str) -> bool:
    if not auth_header.startswith('Bearer '):
        return False

    received_token = auth_header.replace('Bearer ', '')
    return hmac.compare_digest(received_token, expected_token)

Testing Webhooks Locally

If you don’t have a public url to test with you can use smee or a similar service to create a temporary endpoint. Make sure to put that temporary endpoint in the webhook_url field when creating or updating your inbox. You can also do a one-time send to a specific url in the emails page by clicking on the resend icon in the Webhook Status column.

Resend Webhook

Webhook Retry Strategy

If your webhook fails to be delivered (any status code outside of 2XX), BotMailRoom will retry an additional 4 times within a 12 hour period. After that, you can still view the webhook log and resend it manually in the emails page.

Resend Webhook