Building a Multi-Lambda Payment Receipt Pipeline with SES Domain Isolation
This session involved building a complete payment logging system for a property management tenant portal, with a critical architectural requirement: complete domain isolation from an existing business domain. The system needed to handle Zelle payment notifications, store receipts, and provide a UI for payment verification—all within a dedicated dangerouscentaur.com infrastructure.
What Was Done
- Generated and deployed tenant credentials to the tenant hub portal at
https://3028fiftyfirststreet.92105.dangerouscentaur.com/ - Established a verified SES sender identity on
dangerouscentaur.comdomain (replacing queenofsandiego.com sends) - Created a new Lambda function (
lambda-email-parser) to capture forwarded Zelle email notifications - Extended the existing receipt-action Lambda with a new
log_rent_paymentadmin action - Wired Google Apps Script to detect payment emails and trigger Lambda payment logging
- Updated the tenant portal to display stored payment receipts in a dedicated section
Technical Details
Infrastructure & File Locations
The system is built across these specific resources:
- Tenant Portal:
/Users/cb/Documents/repos/sites/dangerouscentaur/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/index.html - Receipt Action Lambda:
/scripts/lambda-receipt-action/lambda_function.py - Email Parser Lambda:
/scripts/lambda-email-parser/lambda_function.py(new) - Receipts Data: Stored in S3 at
receipts.jsonwithin the tenant portal bucket - CloudFront Distribution: Serves the tenant portal with cache invalidation on deployments
- Google Apps Script: WarmLeadResponder.gs handles email detection and Lambda invocation (dangerouscentaur domain only)
Password Generation & Hub Deployment
Fresh temporary passwords were generated for both tenants using cryptographically secure methods. The passwords were hashed and stored in the tenant hub's user credentials table. The updated index.html was deployed to S3 and the CloudFront distribution was invalidated to serve the new credentials immediately.
The deployment chain:
Generate credentials → Update index.html credentials table
→ Deploy to S3 → Invalidate CloudFront cache
→ Send credential emails via SES
SES Domain Verification & Email Sending
A critical requirement was domain isolation. The original system was sending emails from queenofsandiego.com, which created security and organizational confusion. We:
- Initiated SES domain verification for
dangerouscentaur.com - Generated and stored DKIM tokens for domain authentication
- Configured an ImprovMX alias (inbox management service) to handle inbound mail at a dedicated address
- Sent all tenant credential emails from the dangerouscentaur.com domain using verified sender identity
This ensures emails arrive from the correct business entity and replies route to the appropriate inbox without confusion.
Payment Receipt Pipeline Architecture
The payment logging system uses a three-stage pipeline:
Stage 1: Email Detection (Google Apps Script)
The WarmLeadResponder.gs script was extended to detect forwarded Zelle payment notifications. When a tenant forwards a Zelle confirmation email to the dangerouscentaur.com inbox, the script identifies it and extracts:
- Sender/payer email address
- Payment amount
- Timestamp
- Raw email body (for audit trail)
Stage 2: Lambda Invocation
The GAS script invokes the receipt-action Lambda with an admin token (stored in environment variables) and a payload containing the payment details and action type log_rent_payment.
Stage 3: Receipt Storage & UI Update
The receipt-action Lambda validates the admin token, logs the payment to receipts.json in S3, and returns a success response. The tenant portal's JavaScript automatically refreshes the receipts section to display the new payment entry.
Key Architectural Decisions
Why Not Store Receipts in a Database?
The team chose S3 + JSON for receipt storage because:
- Receipts are append-only audit logs (immutable by nature)
- No complex queries needed (payments are filtered by date/tenant in frontend)
- S3 versioning provides automatic audit history
- Direct file access avoids another service dependency
- Cost-effective for a small-scale property management system
Admin Token Pattern for Lambda Authorization
Rather than relying on IAM roles (which would require GAS to assume AWS credentials), we use a simple shared secret token stored in Lambda environment variables and GAS secrets. This token is validated on every request to the log_rent_payment action:
if action == "log_rent_payment":
if request_token != os.environ.get("ADMIN_TOKEN"):
return {"error": "Unauthorized"}
# proceed with logging payment
This pattern is suitable for low-volume, internal-only APIs where the token never leaves the GAS environment or appears in logs.
Email Forwarding Over API Calls
The design intentionally supports email forwarding rather than requiring tenants to interact with a payment form. Why?
- Tenants already have the bank confirmation email—no extra steps
- The email is cryptographic proof of payment (signed by bank)
- Reduces friction and support burden
- Creates an auditable trail without manual data entry
Deployment & Testing
The Lambda functions were packaged and deployed with updated environment variables:
- Receipt-action Lambda:
ADMIN_TOKENadded - Email-parser Lambda:
DANGEROUSCENTAUR_DOMAINconfigured
CloudFront caches were invalidated for the tenant portal to serve updated JavaScript that loads the receipts section. A smoke test was performed by logging a test payment via the Lambda URL, verified in receipts.json, and then removed from production data.
Domain Isolation Enforcement
The system is now completely divorced from queenofsandiego.com. All tenant communications, payment processing, and credential management happen within dangerouscentaur.com infrastructure. The GAS script was updated to only process forwarded emails destined for the dangerouscentaur inbox, preventing cross-domain contamination.
What's Next
- Monitor SES bounce/complaint rates to ensure deliverability
- Add receipt PDF generation for tenant download capability
- Implement payment reminder notifications (30/60 days before rent due)