Prompt
How do I send receipt emails from a SaaS app?
Latest observation
To send receipt emails from a SaaS app, you typically want an automated email flow tied to a successful payment event.
Basic flow
-
Payment succeeds
- Your payment provider (Stripe, Paddle, Braintree, etc.) sends a webhook to your backend.
- Example event:
payment_intent.succeeded,invoice.paid, or equivalent.
-
Your backend verifies the event
- Check the webhook signature so you know it’s really from the provider.
- Ignore duplicate events by storing the event ID or payment ID.
-
Generate receipt data
- Customer name/email
- Order or invoice number
- Date/time
- Amount, currency, tax, discounts
- Line items / plan name
- Billing address or VAT info if needed
- Transaction ID
- Link to downloadable PDF receipt if applicable
-
Send the email
- Use an email service like:
- Postmark
- SendGrid
- Amazon SES
- Mailgun
- Use an HTML template with a plain-text fallback.
- Use an email service like:
-
Optionally store a receipt
- Save a receipt record in your database.
- Generate a PDF only if you need accounting/legal documents.
- Provide a “View receipt” link in the user portal.
Recommended architecture
- Payment provider → webhook → your app
- Your app:
- validates webhook
- records payment
- creates receipt record
- queues email job
- Email worker sends receipt email asynchronously
This avoids slowing down the webhook response and makes retries safer.
Important implementation details
1. Send receipts only after confirmed payment
Don’t send on “payment initiated.” Send only after:
- card charged successfully, or
- invoice marked paid, or
- subscription renewal successfully collected.
2. Make emails idempotent
Webhooks can be delivered more than once. Store:
- webhook event ID
- payment/charge/invoice ID
- “receipt sent” status
Before sending, check whether you already processed it.
3. Include a clear receipt format
A typical receipt email should include:
- company name/logo
- receipt number
- date
- amount paid
- payment method last 4 digits
- purchased product/plan
- tax breakdown
- support contact
- link to receipt PDF or billing page
4. Handle failed email delivery
If email sending fails:
- retry with backoff
- log the failure
- show the receipt in the user’s billing dashboard as a backup
5. Use a transactional email provider
Don’t send receipts from your regular app mail server if you can avoid it. Transactional providers give you:
- higher deliverability
- bounce handling
- delivery logs
- templates
- tracking
Example event-driven approach
- User pays $29
- Stripe sends
invoice.paid - Your backend verifies webhook
- You create
receipt_12345 - You enqueue
send_receipt_email(receipt_12345) - Worker sends email to
customer@example.com
If you use Stripe
Stripe can generate invoices/receipts for you in some cases, but many SaaS apps still send their own branded receipt emails for consistency. If you want Stripe-managed receipts:
- enable receipt emails in Stripe settings
- configure invoice settings and branding
- use webhooks to sync your records
If you want custom receipts:
- listen to
checkout.session.completed,invoice.paid, orpayment_intent.succeeded - generate your own email template
Security and compliance
- Don’t include full card numbers.
- Be careful with tax and invoicing rules depending on country.
- If you sell subscriptions, distinguish between:
- receipt for payment confirmation
- invoice for billing document
Simple checklist
- Set up payment webhooks
- Verify webhook signatures
- Make processing idempotent
- Create receipt data
- Send via transactional email service
- Add retry/failure handling
- Provide a billing page with receipt history
If you want, I can also show:
- a Stripe + Node.js example,
- a Python/Django example, or
- a receipt email template you can copy.