来自 Stripe Webhooks 的多语言邮件

在全球范围内扩展 SaaS 会遇到隐藏的陷阱。我们在 Stripe webhooks 中发现了一个。

我们的系统向说英语的用户发送了日语版的购买确认、续费和失败通知。这个 Bug 存在了好几个月,因为它一直很隐蔽。

我们通过从货币推断语言解决了这个问题。

我们考虑了三种设计方案:

  • 方案 A:在数据库中存储语言。这需要对旧用户进行数据迁移和回填。
  • 方案 B:从 Stripe API 获取。这会增加额外的 API 调用,而且许多客户并没有设置首选语言区域。
  • 方案 C:使用 webhook payload 中的货币。这种方式是免费的,不需要更改数据库,并且可以立即对现有用户生效。

我们选择了方案 C。货币在购买时刻是一个固定的信号。如果用户使用 USD 支付,他们会收到英语邮件;如果使用 JPY 支付,他们会收到日语邮件。

逻辑很简单:

function lang_from_currency(string $currency): string {
    $en_currencies = ['usd'];
    return in_array(strtolower($currency), $en_currencies, true) ? 'en' : 'ja';
}

这适用于所有四种主要的 Stripe 事件:

  • checkout.session.completed
  • invoice.payment_succeeded
  • invoice.payment_failed
  • customer.subscription.updated

我们还发现了 PHP 中的一个技术陷阱。

使用 mb_language('Japanese') 会将主题行编码为 ISO-2022-JP。如果你在这种设置下发送英语主题行,Gmail 和 Outlook 会将其视为异常编码。这会提高你的垃圾邮件评分。

解决方法是根据语言切换编码:

mb_language($lang === 'en' ? 'uni' : 'Japanese');

使用 'uni' 会采用 UTF-8 Base64 编码。这能让你的邮件避免进入垃圾邮件箱。

从这次修复中得到的三个教训:

  • 利用事件 payload。如果数据已经存在于 webhook 中,就不要去动数据库。这可以降低风险并减少维护工作。
  • 注意编码。如果你支持多种语言,请确保主题行的编码与内容匹配,以避免触发垃圾邮件过滤器。
  • 审计硬编码值。当你走向国际化时,检查一下你的通知函数是否包含硬编码的语言设置。

无状态设计使你的系统更易于维护,也更不容易出错。

Source: https://dev.to/susumun/multilingual-emails-from-a-stripe-webhook-inferring-language-from-currency-i99