postmark-webhooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Postmark Webhooks

Postmark Webhooks

When to Use This Skill

何时使用该Skill

  • Setting up Postmark webhook handlers for email event tracking
  • Processing email delivery events (bounce, delivered, open, click)
  • Handling spam complaints and subscription changes
  • Implementing email engagement analytics
  • Troubleshooting webhook authentication issues
  • 搭建用于邮件事件追踪的Postmark webhook处理器
  • 处理邮件投递事件(退信、投递成功、打开、点击)
  • 处理垃圾邮件投诉和订阅变更
  • 实现邮件互动分析
  • 排查webhook认证问题

Essential Code

核心代码

Authentication

认证

Postmark does NOT use signature verification. Instead, webhooks are authenticated by including credentials in the webhook URL itself.
javascript
// Express - Basic Auth in URL
// Configure webhook URL in Postmark as:
// https://username:password@yourdomain.com/webhooks/postmark

app.post('/webhooks/postmark', express.json(), (req, res) => {
  // Basic auth is handled by your web server or proxy
  // Additional validation can check expected payload structure

  const event = req.body;

  // Validate expected fields exist
  if (!event.RecordType || !event.MessageID) {
    return res.status(400).send('Invalid payload structure');
  }

  // Process event
  console.log(`Received ${event.RecordType} event for ${event.Email}`);

  res.sendStatus(200);
});

// Alternative: Token in URL
// Configure webhook URL as:
// https://yourdomain.com/webhooks/postmark?token=your-secret-token

app.post('/webhooks/postmark', express.json(), (req, res) => {
  const token = req.query.token;

  if (token !== process.env.POSTMARK_WEBHOOK_TOKEN) {
    return res.status(401).send('Unauthorized');
  }

  const event = req.body;
  console.log(`Received ${event.RecordType} event`);

  res.sendStatus(200);
});
Postmark不使用签名验证,而是通过在webhook URL中包含凭证来进行认证。
javascript
// Express - URL中的基础认证
// 在Postmark中配置webhook URL为:
// https://username:password@yourdomain.com/webhooks/postmark

app.post('/webhooks/postmark', express.json(), (req, res) => {
  // 基础认证由你的web服务器或代理处理
  // 可额外验证预期的负载结构

  const event = req.body;

  // 验证必填字段是否存在
  if (!event.RecordType || !event.MessageID) {
    return res.status(400).send('Invalid payload structure');
  }

  // 处理事件
  console.log(`Received ${event.RecordType} event for ${event.Email}`);

  res.sendStatus(200);
});

// 替代方案:URL中的Token
// 配置webhook URL为:
// https://yourdomain.com/webhooks/postmark?token=your-secret-token

app.post('/webhooks/postmark', express.json(), (req, res) => {
  const token = req.query.token;

  if (token !== process.env.POSTMARK_WEBHOOK_TOKEN) {
    return res.status(401).send('Unauthorized');
  }

  const event = req.body;
  console.log(`Received ${event.RecordType} event`);

  res.sendStatus(200);
});

Handling Multiple Events

处理多类事件

javascript
// Postmark sends one event per request (not batched)
app.post('/webhooks/postmark', express.json(), (req, res) => {
  const event = req.body;

  switch (event.RecordType) {
    case 'Bounce':
      console.log(`Bounce: ${event.Email} - ${event.Type} - ${event.Description}`);
      // Update contact as undeliverable
      break;

    case 'SpamComplaint':
      console.log(`Spam complaint: ${event.Email}`);
      // Remove from mailing list
      break;

    case 'Open':
      console.log(`Email opened: ${event.Email} at ${event.ReceivedAt}`);
      // Track engagement
      break;

    case 'Click':
      console.log(`Link clicked: ${event.Email} - ${event.OriginalLink}`);
      // Track click-through rate
      break;

    case 'Delivery':
      console.log(`Delivered: ${event.Email} at ${event.DeliveredAt}`);
      // Confirm delivery
      break;

    case 'SubscriptionChange':
      console.log(`Subscription change: ${event.Email} - ${event.ChangedAt}`);
      // Update subscription preferences
      break;

    case 'Inbound':
      console.log(`Inbound email from: ${event.Email} - Subject: ${event.Subject}`);
      // Process incoming email
      break;

    case 'SMTP API Error':
      console.log(`SMTP API error: ${event.Email} - ${event.Error}`);
      // Handle API error, maybe retry
      break;

    default:
      console.log(`Unknown event type: ${event.RecordType}`);
  }

  res.sendStatus(200);
});
javascript
// Postmark每次请求发送一个事件(不批量发送)
app.post('/webhooks/postmark', express.json(), (req, res) => {
  const event = req.body;

  switch (event.RecordType) {
    case 'Bounce':
      console.log(`Bounce: ${event.Email} - ${event.Type} - ${event.Description}`);
      // 将联系人标记为无法投递
      break;

    case 'SpamComplaint':
      console.log(`Spam complaint: ${event.Email}`);
      // 从邮件列表中移除
      break;

    case 'Open':
      console.log(`Email opened: ${event.Email} at ${event.ReceivedAt}`);
      // 追踪互动情况
      break;

    case 'Click':
      console.log(`Link clicked: ${event.Email} - ${event.OriginalLink}`);
      // 追踪点击率
      break;

    case 'Delivery':
      console.log(`Delivered: ${event.Email} at ${event.DeliveredAt}`);
      // 确认投递成功
      break;

    case 'SubscriptionChange':
      console.log(`Subscription change: ${event.Email} - ${event.ChangedAt}`);
      // 更新订阅偏好
      break;

    case 'Inbound':
      console.log(`Inbound email from: ${event.Email} - Subject: ${event.Subject}`);
      // 处理收到的邮件
      break;

    case 'SMTP API Error':
      console.log(`SMTP API error: ${event.Email} - ${event.Error}`);
      // 处理API错误,可尝试重试
      break;

    default:
      console.log(`Unknown event type: ${event.RecordType}`);
  }

  res.sendStatus(200);
});

Common Event Types

常见事件类型

EventRecordTypeDescriptionKey Fields
Bounce
Bounce
Hard/soft bounce or blocked emailEmail, Type, TypeCode, Description
Spam Complaint
SpamComplaint
Recipient marked as spamEmail, BouncedAt
Open
Open
Email opened (requires open tracking)Email, ReceivedAt, Platform, UserAgent
Click
Click
Link clicked (requires click tracking)Email, ClickedAt, OriginalLink
Delivery
Delivery
Successfully deliveredEmail, DeliveredAt, Details
Subscription Change
SubscriptionChange
Unsubscribe/resubscribeEmail, ChangedAt, SuppressionReason
Inbound
Inbound
Incoming email receivedEmail, FromFull, Subject, TextBody, HtmlBody
SMTP API Error
SMTP API Error
SMTP API call failedEmail, Error, ErrorCode, MessageID
事件RecordType描述关键字段
退信
Bounce
硬退信/软退信或邮件被拦截Email, Type, TypeCode, Description
垃圾邮件投诉
SpamComplaint
收件人标记邮件为垃圾邮件Email, BouncedAt
邮件打开
Open
邮件被打开(需开启打开追踪)Email, ReceivedAt, Platform, UserAgent
链接点击
Click
链接被点击(需开启点击追踪)Email, ClickedAt, OriginalLink
投递成功
Delivery
邮件成功投递Email, DeliveredAt, Details
订阅变更
SubscriptionChange
取消订阅/重新订阅Email, ChangedAt, SuppressionReason
收到邮件
Inbound
收到 incoming 邮件Email, FromFull, Subject, TextBody, HtmlBody
SMTP API错误
SMTP API Error
SMTP API调用失败Email, Error, ErrorCode, MessageID

Environment Variables

环境变量

bash
undefined
bash
undefined

For token-based authentication

基于Token的认证

POSTMARK_WEBHOOK_TOKEN="your-secret-token-here"
POSTMARK_WEBHOOK_TOKEN="your-secret-token-here"

For basic auth (if not using URL-embedded credentials)

基础认证(若不使用URL嵌入的凭证)

WEBHOOK_USERNAME="your-username" WEBHOOK_PASSWORD="your-password"
undefined
WEBHOOK_USERNAME="your-username" WEBHOOK_PASSWORD="your-password"
undefined

Security Best Practices

安全最佳实践

  1. Always use HTTPS - Never configure webhooks with HTTP URLs
  2. Use strong credentials - Generate long, random tokens or passwords
  3. Validate payload structure - Check for expected fields before processing
  4. Implement IP allowlisting - Postmark publishes their IP ranges
  5. Consider using a webhook gateway - Like Hookdeck for additional security layers
  1. 始终使用HTTPS - 绝不要使用HTTP URL配置webhook
  2. 使用强凭证 - 生成长且随机的Token或密码
  3. 验证负载结构 - 处理前检查必填字段是否存在
  4. 实施IP白名单 - Postmark会公布其IP范围
  5. 考虑使用webhook网关 - 例如Hookdeck,以增加额外的安全层

Local Development

本地开发

For local webhook testing, use Hookdeck CLI:
bash
brew install hookdeck/hookdeck/hookdeck
hookdeck listen 3000 --path /webhooks/postmark
No account required. Provides local tunnel + web UI for inspecting requests.
如需本地测试webhook,可使用Hookdeck CLI:
bash
brew install hookdeck/hookdeck/hookdeck
hookdeck listen 3000 --path /webhooks/postmark
无需注册账号,提供本地隧道和用于查看请求的Web UI。

Resources

参考资源

  • overview.md - What Postmark webhooks are, common event types
  • setup.md - Configure webhooks in Postmark dashboard
  • verification.md - Authentication methods and security best practices
  • examples/ - Complete implementations for Express, Next.js, and FastAPI
  • overview.md - Postmark webhook是什么,常见事件类型
  • setup.md - 在Postmark控制台配置webhook
  • verification.md - 认证方法和安全最佳实践
  • examples/ - Express、Next.js和FastAPI的完整实现示例

Recommended: webhook-handler-patterns

推荐:webhook-handler-patterns

For production-ready webhook handling, also install the webhook-handler-patterns skill:
如需生产环境可用的webhook处理方案,还可安装webhook-handler-patterns skill:

Related Skills

相关Skill