Stripe Webhook을 통한 다국어 이메일 발송

SaaS를 글로벌로 확장하는 데에는 숨겨진 함정들이 있습니다. 저희는 Stripe webhook에서 그 함정 하나를 발견했습니다.

저희 시스템은 영어를 사용하는 사용자에게 구매 확인, 갱신 및 결제 실패 알림을 일본어로 보냈습니다. 이 버그는 별다른 문제가 겉으로 드러나지 않았기에 몇 달 동안 지속되었습니다.

저희는 통화(currency)를 통해 언어를 추론하는 방식으로 이 문제를 해결했습니다.

세 가지 설계 옵션을 검토했습니다:

  • 옵션 A: 데이터베이스에 언어 정보를 저장합니다. 이 방식은 기존 사용자를 위한 마이그레이션과 백필(backfill) 작업이 필요합니다.
  • 옵션 B: Stripe API에서 정보를 가져옵니다. 이 방식은 추가적인 API 호출을 발생시키며, 많은 고객이 선호하는 로케일(locale)을 설정하지 않는다는 단점이 있습니다.
  • 옵션 C: webhook 페이로드에 포함된 통화 정보를 사용합니다. 이 방식은 비용이 들지 않고, 데이터베이스 변경이 필요 없으며, 기존 사용자에게도 즉시 적용됩니다.

저희는 옵션 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를 사용하게 됩니다. 이를 통해 이메일이 스팸함으로 빠지는 것을 방지할 수 있습니다.

이번 해결 과정을 통해 얻은 세 가지 교훈입니다:

  • 이벤트 페이로드를 활용하세요. 데이터가 이미 webhook에 있다면 데이터베이스를 건드리지 마세요. 이는 리스크와 유지보수 비용을 줄여줍니다.
  • 인코딩을 주의 깊게 살피세요. 다국어를 지원하는 경우, 스팸 필터를 피하기 위해 제목의 인코딩이 본문 내용과 일치하는지 확인해야 합니다.
  • 하드코딩된 값을 점검하세요. 글로벌 서비스를 운영할 때는 알림 기능에 언어 설정이 하드코딩되어 있지 않은지 확인해야 합니다.

상태를 저장하지 않는(stateless) 설계는 시스템을 유지보수하기 쉽게 만들고, 장애 발생 가능성을 낮춰줍니다.

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