feat: implement MailGun webhook service for logging email events
Implemented a production-ready TypeScript/Express.js service to receive and log MailGun webhook events (delivered, failed, opened, clicked, etc.). Key features: - Webhook endpoint (POST /webhook) with comprehensive event logging - Full TypeScript type definitions for all MailGun event types - Prometheus metrics integration for monitoring - Health check endpoint (GET /ping) - Comprehensive Jest test suite with 87.76% coverage - Docker containerization with build scripts Removed template/example code: - All SQL/MSSQL dependencies and related code - Example auth router and middleware - PRTG metrics support (simplified to Prometheus only) - Unused middleware (CORS, IP whitelist, request parsing/validation) - Template documentation (kept only MailGun webhook API spec) The service is clean, minimal, and focused solely on receiving and logging MailGun webhook events to the console. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
176
mailgun-webhook/docs/MAILGUN_WEBHOOK_API_SPEC.md
Normal file
176
mailgun-webhook/docs/MAILGUN_WEBHOOK_API_SPEC.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# MailGun Webhook API Specification
|
||||
|
||||
## Overview
|
||||
|
||||
This document specifies the API for receiving webhook events from MailGun. The service logs all received event data to the console for monitoring and debugging purposes.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### POST /webhook
|
||||
|
||||
Receives webhook events from MailGun when email events occur.
|
||||
|
||||
#### Request Format
|
||||
|
||||
- **Method**: POST
|
||||
- **Content-Type**: `application/x-www-form-urlencoded` or `multipart/form-data`
|
||||
- **Headers**:
|
||||
- No custom headers required for initial implementation
|
||||
|
||||
#### Request Parameters
|
||||
|
||||
MailGun sends various parameters depending on the event type. Common parameters include:
|
||||
|
||||
**Event Identification:**
|
||||
- `event` (string) - Type of event (delivered, failed, opened, clicked, bounced, complained, unsubscribed)
|
||||
- `timestamp` (number) - Unix timestamp when the event occurred
|
||||
- `token` (string) - Randomly generated string for message signature verification
|
||||
- `signature` (string) - String with hexadecimal digits for signature verification
|
||||
|
||||
**Message Information:**
|
||||
- `message-id` (string) - MailGun message ID
|
||||
- `recipient` (string) - Email address of the recipient
|
||||
- `domain` (string) - Domain from which the email was sent
|
||||
- `Message-Id` (string) - SMTP Message-ID header
|
||||
|
||||
**Event-Specific Parameters:**
|
||||
|
||||
For **delivered** events:
|
||||
- `message-headers` (string) - JSON string of message headers
|
||||
|
||||
For **failed** events:
|
||||
- `severity` (string) - Severity level (temporary/permanent)
|
||||
- `reason` (string) - Reason for failure
|
||||
- `notification` (string) - Detailed notification message
|
||||
|
||||
For **opened** events:
|
||||
- `city` (string) - City where email was opened
|
||||
- `country` (string) - Country code
|
||||
- `device-type` (string) - Device type (desktop/mobile/tablet)
|
||||
- `client-os` (string) - Operating system
|
||||
- `client-name` (string) - Email client name
|
||||
- `ip` (string) - IP address
|
||||
|
||||
For **clicked** events:
|
||||
- `url` (string) - URL that was clicked
|
||||
- `city`, `country`, `device-type`, `client-os`, `client-name`, `ip` - Same as opened events
|
||||
|
||||
For **bounced** events:
|
||||
- `code` (string) - SMTP error code
|
||||
- `error` (string) - Detailed error message
|
||||
- `notification` (string) - Bounce notification
|
||||
|
||||
For **complained** events:
|
||||
- No additional parameters
|
||||
|
||||
For **unsubscribed** events:
|
||||
- No additional parameters
|
||||
|
||||
#### Success Response
|
||||
|
||||
- **HTTP Status**: 200 OK
|
||||
- **Content-Type**: `application/json`
|
||||
- **Response Body**:
|
||||
```json
|
||||
{
|
||||
"status": "received",
|
||||
"message": "Webhook event logged successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Responses
|
||||
|
||||
**Invalid Request (400 Bad Request)**:
|
||||
- **Content-Type**: `application/json`
|
||||
- **Response Body**:
|
||||
```json
|
||||
{
|
||||
"error": "Invalid request format"
|
||||
}
|
||||
```
|
||||
|
||||
**Server Error (500 Internal Server Error)**:
|
||||
- **Content-Type**: `application/json`
|
||||
- **Response Body**:
|
||||
```json
|
||||
{
|
||||
"error": "Internal server error"
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Flow
|
||||
|
||||
1. **Receive webhook POST request** from MailGun
|
||||
2. **Parse request body** (form-urlencoded or multipart data)
|
||||
3. **Extract event data** from request parameters
|
||||
4. **Log event data to console** with structured formatting:
|
||||
- Event type
|
||||
- Timestamp (both Unix and human-readable)
|
||||
- Recipient
|
||||
- All additional event-specific parameters
|
||||
5. **Return success response** to MailGun
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### Missing Event Type
|
||||
- **Detection**: Check if `event` parameter is present
|
||||
- **Handling**: Log warning and return 400 Bad Request
|
||||
|
||||
### Malformed Timestamp
|
||||
- **Detection**: Check if `timestamp` can be parsed as number
|
||||
- **Handling**: Log with current timestamp instead, continue processing
|
||||
|
||||
### Large Payload
|
||||
- **Detection**: Monitor request body size
|
||||
- **Handling**: Log truncated data if exceeds reasonable size
|
||||
|
||||
### Duplicate Events
|
||||
- **Detection**: MailGun may send duplicate webhooks
|
||||
- **Handling**: Log all events (no deduplication in initial implementation)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Future Enhancements
|
||||
For production deployment, consider:
|
||||
- **Signature Verification**: Verify webhook authenticity using `timestamp`, `token`, and `signature`
|
||||
- **IP Whitelisting**: Restrict to MailGun's IP ranges
|
||||
- **Rate Limiting**: Prevent abuse
|
||||
|
||||
## Database Integration
|
||||
|
||||
- **Current Implementation**: No database operations required
|
||||
- **Future Enhancement**: Store events in database for analysis
|
||||
|
||||
## Third-Party API Calls
|
||||
|
||||
- **Current Implementation**: No third-party API calls
|
||||
- **Future Enhancement**: Could integrate with notification services
|
||||
|
||||
## Logging Format
|
||||
|
||||
Console output format:
|
||||
```
|
||||
========================================
|
||||
MailGun Webhook Event Received
|
||||
========================================
|
||||
Event Type: delivered
|
||||
Timestamp: 1234567890 (2024-01-01 12:00:00 UTC)
|
||||
Recipient: user@example.com
|
||||
Domain: mail.example.com
|
||||
Message ID: <20240101120000.1.ABC123@mail.example.com>
|
||||
----------------------------------------
|
||||
Additional Parameters:
|
||||
{
|
||||
"message-headers": "[...]",
|
||||
"token": "...",
|
||||
"signature": "..."
|
||||
}
|
||||
========================================
|
||||
```
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Use Express body-parser middleware for form data parsing
|
||||
- All logging should use structured logger (debug package)
|
||||
- Maintain type safety with TypeScript interfaces for event data
|
||||
- Follow template's error handling patterns
|
||||
Reference in New Issue
Block a user