diff --git a/.env.example b/.env.example index 8162f7a..74b212d 100644 --- a/.env.example +++ b/.env.example @@ -18,6 +18,7 @@ POSTMARK_API_KEY=your_postmark_server_token BTCPAY_URL=https://payment.nxtgroup.org FROM_EMAIL=billing@nxtgroup.org BCC_EMAIL=admin@nxtgroup.org,finance@nxtgroup.org +WEBHOOK_TEST_EMAIL=erling@nxtgroup.org DEBUG=false # Test Postmark after deploy (docker exec or Portainer console): diff --git a/SETUP.md b/SETUP.md index 0d24cd8..3ff23eb 100644 --- a/SETUP.md +++ b/SETUP.md @@ -96,6 +96,8 @@ The Secret in BTCPay must **exactly match** `BTCPAY_WEBHOOK_SECRET` in Portainer ## 6. Test Postmark +Optional: set `WEBHOOK_TEST_EMAIL` (defaults to first `BCC_EMAIL` address). BTCPay’s **Send test** for `InvoiceReceivedPayment` delivers a Postmark test email to that address. + Portainer → container console: ```bash diff --git a/WEBHOOK.md b/WEBHOOK.md index 4af126f..c84d1e5 100644 --- a/WEBHOOK.md +++ b/WEBHOOK.md @@ -56,6 +56,10 @@ GET {BTCPAY_URL}/api/v1/stores/{storeId}/invoices/{invoiceId} 5. `0 < amountPaid < amount` 6. `metadata.buyerEmail` is set +## BTCPay UI test events + +Invoice IDs containing `__test__` (BTCPay’s “Send test” button) skip the API fetch and trigger a Postmark test email to `WEBHOOK_TEST_EMAIL`, or the first `BCC_EMAIL` address if unset. The email includes a red **THIS IS A TEST TRANSACTIONAL EMAIL, PLEASE IGNORE.** banner. + ## Response codes | Code | Meaning | diff --git a/app.py b/app.py index 59a83b8..f99e46e 100644 --- a/app.py +++ b/app.py @@ -18,8 +18,11 @@ BTCPAY_API_KEY = os.getenv("BTCPAY_API_KEY") POSTMARK_API_KEY = os.getenv("POSTMARK_API_KEY") FROM_EMAIL = os.getenv("FROM_EMAIL", "billing@nxtgroup.org") BCC_EMAIL = os.getenv("BCC_EMAIL", "admin@nxtgroup.org") +WEBHOOK_TEST_EMAIL = os.getenv("WEBHOOK_TEST_EMAIL") DEBUG = os.getenv("DEBUG", "false").lower() in ("true", "1", "yes") +TEST_EMAIL_BANNER = "THIS IS A TEST TRANSACTIONAL EMAIL, PLEASE IGNORE." + logger = logging.getLogger("btcpaymailer") logger.setLevel(logging.DEBUG if DEBUG else logging.INFO) if not logger.handlers: @@ -57,11 +60,30 @@ def verify_btcpay_webhook(body: bytes, signature: str | None, secret: str | None return hmac.compare_digest(expected, signature) -def get_html_template(order_id, invoice_id, amount, currency, amount_paid, remaining): +def is_btcpay_test_invoice(invoice_id): + return bool(invoice_id and "__test__" in invoice_id) + + +def get_webhook_test_recipient(): + if WEBHOOK_TEST_EMAIL: + return WEBHOOK_TEST_EMAIL + if BCC_EMAIL: + return BCC_EMAIL.split(",")[0].strip() + return FROM_EMAIL + + +def get_html_template(order_id, invoice_id, amount, currency, amount_paid, remaining, test_mode=False): + test_banner = "" + if test_mode: + test_banner = f""" +