Skip to content

Commit 8d3faca

Browse files
committed
Rewrite example
1 parent 608c183 commit 8d3faca

2 files changed

Lines changed: 23 additions & 38 deletions

File tree

‎README.md‎

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -248,31 +248,6 @@ The same situation applies to both `client.batch_send()` and `client.sending_api
248248
- Webhooks management – [`webhooks/webhooks.py`](examples/webhooks/webhooks.py)
249249
- Verifying webhook signatures – [`webhooks/verify_signature.py`](examples/webhooks/verify_signature.py)
250250

251-
#### Verifying webhook signatures
252-
253-
Mailtrap signs every outbound webhook with HMAC-SHA256 and sends the
254-
lowercase hex digest in the `Mailtrap-Signature` header. Verify the signature
255-
against the raw request body using the `signing_secret` returned when you
256-
created the webhook:
257-
258-
```python
259-
import mailtrap as mt
260-
261-
# `raw_body` must be the unparsed request body bytes — do NOT re-serialize
262-
# the parsed JSON, as that may reorder keys and invalidate the signature.
263-
valid = mt.verify_signature(
264-
raw_body,
265-
request.headers.get("Mailtrap-Signature", ""),
266-
os.environ["MAILTRAP_WEBHOOK_SIGNING_SECRET"],
267-
)
268-
269-
if not valid:
270-
abort(401)
271-
```
272-
273-
The helper performs a constant-time comparison and returns `False` (rather
274-
than raising) for empty, missing, or malformed signatures.
275-
276251
### Suppressions API:
277252
- Suppressions (find & delete) – [`suppressions/suppressions.py`](examples/suppressions/suppressions.py)
278253

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
import hashlib
2-
import hmac
1+
import os
2+
from wsgiref.simple_server import make_server
33

44
import mailtrap as mt
55

6-
# --- Direct verification (e.g. for unit tests or custom routers) ----------
7-
payload = '{"event":"delivery","message_id":"abc-123"}'
8-
signing_secret = "8d9a3c0e7f5b2d4a6c1e9f8b3a7d5c2e"
9-
signature = hmac.new(
10-
signing_secret.encode("utf-8"),
11-
payload.encode("utf-8"),
12-
hashlib.sha256,
13-
).hexdigest()
14-
15-
if not mt.verify_signature(payload, signature, signing_secret):
16-
raise SystemExit("Signature verification failed!")
6+
SIGNING_SECRET = os.environ["MAILTRAP_WEBHOOK_SIGNING_SECRET"]
7+
8+
9+
def app(environ, start_response):
10+
# Use the raw request body — parsing and re-serializing the JSON may
11+
# reorder keys or alter whitespace and invalidate the signature.
12+
length = int(environ.get("CONTENT_LENGTH") or 0)
13+
payload = environ["wsgi.input"].read(length).decode("utf-8")
14+
signature = environ.get("HTTP_MAILTRAP_SIGNATURE", "")
15+
16+
if not mt.verify_signature(payload, signature, SIGNING_SECRET):
17+
start_response("401 Unauthorized", [("Content-Type", "text/plain")])
18+
return [b"Invalid signature"]
19+
20+
start_response("200 OK", [("Content-Type", "text/plain")])
21+
return [b""]
22+
23+
24+
if __name__ == "__main__":
25+
with make_server("", 9292, app) as server:
26+
server.serve_forever()

0 commit comments

Comments
 (0)