After a payment, the customer expects an email: "we got your money". A shop doesn't run its own mail server. It calls a mail service through its API, like the supplier and the payment provider. Ours lives at http://127.0.0.1:8003: you POST JSON with "to", "subject" and "body" to /send, and it answers 202 Accepted, which means "I have it, I'll deliver it".
The email's text is built from pieces joined with +. Numbers must become text with str() first, or Python stops with a TypeError:
count = 3
text = "You have " + str(count) + " new messages"
print(text) # You have 3 new messages
Put the email in a helper function, so it has its own place and other code can send it too. Call it from pay_order only once the order is saved as paid: a declined card returns earlier, and so does a retry with the same idempotency key, so neither sends an email. The checker adds GET /check/sent, the list of emails the mail service received:
POST /orders/8/pay (Idempotency-Key: 5f1d7c9e-…) → 201 {"amount": 80, "order_id": 8, "payment_id": "pay_1"}
GET /check/sent → 200 [{"body": "Hello Eva Rossi, we received your payment of 80. Thank you!", "id": 1, "subject": "Your order 8 is paid", "to": "eva@example.com"}]
POST /orders/8/pay (the same key) → 201 {"amount": 80, "order_id": 8, "payment_id": "pay_1"}
POST /orders/9/pay → 402 {"error": "Payment declined", "reason": "card_declined"}
POST /orders/10/pay → 201 {"amount": 21, "order_id": 10, "payment_id": "pay_2"}
GET /check/sent → 200 [Eva's email, {"body": "Hello Chloe Ng, we received your payment of 21. Thank you!", "id": 2, "subject": "Your order 10 is paid", "to": "chloe@example.com"}]
Your task: add the constant MAIL, then write send_receipt(order_id): it finds the order and its customer, builds the subject and the body, and POSTs them to MAIL + "/send", returning the mail service's answer. Call it in pay_order right after the commit.
Assignment
Follow the Coding Tutorial to write the send_receipt helper and send a receipt after each successful payment.
Hint
The order has a customer_id; the name and the email are in the customers table. Wrap order_id and the total in str(). A function runs only when it's called: until pay_order calls the helper, GET /check/sent stays empty.
Free plan: 30 tutor messages. PRO is unlimited.
