SendGridでメールが文字化けする場合の傾向と対策

SendGridでメール送信する際に見かける文字化けの傾向と対策についてまとめます。他にもあるよってことであればコメントいただけると嬉しいです。

# 一般的な文字化けの定義
メールに限らず「文字化け」という現象はコンピュータを扱う際によく見かけると思います。例えば、ウィキペディアでは[こんな感じで定義されています](https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91)。

# 本記事での文字化けの定義
上述の定義では技術的な側面が主たる要因として挙げられていますが、現実には人間的な側面（例えば勘違いとか、知らなかったとか）も多分にあるのではないかと思います。例えば、以下のような状況が考えられます。

- 送信者が意図した内容と異なるメールが送信されてしまっていた
- 送信者が意図した内容を受信側が理解できていなかった

本記事での文字化けの定義にはこのあたりも含めて話を進めようと思います。

# 傾向と対策

それでは、具体的なケースを列挙していきます。文字化けが発生している場合、送信されたメッセージが受信者のもとに届けられ、表示されるまでの間でどこかに問題があるはずです。そこで上流から下流に向かって一つずつ可能性を潰していき原因を特定します。話を整理するため、文字化けの発生原因を以下3つのパートに分けます。

- 送信側に原因がある
- SendGridに原因がある
- 受信側に原因がある

ただ、メールの場合、受信者が使っているクライアントの種類や設定を送信者の意志でどうにかできるわけではないので、原因がわかったとしても打てる対策に限りがある場合があります。最悪の場合、**受信者が読める形式で送ってあげる**という泥臭い対応も覚悟する必要があります。

## 送信側に原因があるケース

SendGridではメールの送信方法には大きくわけて[**SMTP**と**Web API**](https://sendgrid.kke.co.jp/docs/Tutorials/A_Transaction_Mail/send_transaction_mail.html)の二つの方法があります。この他に[マーケティングメール機能](https://sendgrid.kke.co.jp/docs/User_Manual_JP/Legacy_Newsletter/Legacy_Newsletter_Features/index.html)や[マーケティングキャンペーン機能](https://sendgrid.kke.co.jp/docs/User_Manual_JP/Marketing_Campaigns/index.html)といった一斉配信向けの機能もありますが、文字化け問題の切り分けの観点からするとこれらはWeb APIと同等です。

### SMTPで送信している
SMTPで送信する場合、件名と本文ではエンコード方式が異なるので、どちらが文字化けしているかによって見るべきポイントが変わってきます。また、文字列の一部が文字化けしている場合、使用している文字コード範囲外の文字が使用されている可能性があります。共通しているのは文字コードと符号化方式を意識することです。エンコードの確認には[エンコードマニアックス](http://www.encodemaniax.com/)というサイトが便利です。

- **件名が文字化けする**  
件名を含むメールヘッダにはそもそも非ASCII文字を含めることができません。そこでこれらの文字は[RFC2047](https://tools.ietf.org/html/rfc2047)に従ってエンコードしてあげる必要があります。
日本語でわかりやすいのは[こちら](http://www.kanzaki.com/docs/jis-mail.html#MIME-header)。SMTPの送信ログ（SendGridに対する送信リクエスト）でSubjectヘッダの内容が正しくエンコードされているか確認してみるとよいでしょう。  
- **本文が文字化けする**  
本文での非ASCII文字のエンコード方式については、[RFC2045](https://tools.ietf.org/html/rfc2045)で定められています。文字コードはContent-Typeヘッダのcharsetパラメータで、符号化方式はContent-Transfer-Encodingヘッダで[指定します](https://ja.wikipedia.org/wiki/Multipurpose_Internet_Mail_Extensions#MIME-Version)。送信リクエストにてこれらのヘッダ上の宣言と本文の内容が整合しているか確認してください。また、Content-Transfer-Encodingで**使用可能なのは7bit、quoted-printable、base64**です。8bitを使用すると自動的にquoted-printableに変換され文字化けの原因となるので8bitは使用できないと考えてください。  
- **一部が文字化けする**  
一部が文字化けする場合、メール送信に使用している文字コード範囲外の文字が含まれている可能性（有名なのはISO-2022-JPで半角カナを使用する、など）があります。例えばメール送信時に文字コードの変換を行っている場合には注意が必要です。
  - 変換が正しく行われているか？
  - 変換先の文字コードで使用できない文字が含まれていないか？

以上のように、SMTPで送信する場合、文字コードと符号化方式に関して気をつかう必要があります。推奨は、**送信側システム内の文字コードをUTF-8で統一して文字コードの変換を排除する＋送信時の符号化方式はBase64またはquoted-printableいずれかを使用する**、です。さらに、テキスト/HTMLのalternativeなマルチパートメールで問題ないということであれば、後述するWeb APIを利用することでさらにこの辺のややこしさから解放されます。

### Web APIで送信している
SMTPと違ってWeb APIを使用するとこのあたりの負担がぐっと減ります。**Web APIで使える文字コードはUTF-8のみ**で、符号化方式は指定できません（SendGridが自動的にquoted-printableで送信します）。例えば、スクリプトやソースコードがSJISで、ハードコーディングされた文字列をパラメータに指定したり、ユーザからの入力などによって、Web APIのパラメータにUTF-8以外を指定すると文字化けしてしまうので、とにかくUTF-8以外の文字が混入することを防いでください。

## SendGridに原因があるケース
SendGridの機能上、メールの一部を置換して送信するケースがあります。人によってはこれを文字化けと表現することがあるようです。意図しない設定が有効化されていないか確認しましょう。

### Click Tracking機能
テキストメール本文内のURLが異常に長いものに置き換えられる現象も「文字化け」と表現される場合があるようです。これは[Click Tracking機能](https://sendgrid.kke.co.jp/docs/User_Manual_JP/Settings/tracking.html#-Click-Tracking)（デフォルト有効）が原因と考えられます。この機能は、メール本文内のURLがクリックされたことをSendGridにて認識するため、自動的にトラッキング用URLに置換してメール送信します。トラッキングよりもテキストパートの見た目が重要、ということであれば[「Enable click tracking in plain text emails」オプションを無効化](https://app.sendgrid.com/settings/tracking)することでテキストパートのURL置換を無効化できます。

ここまでの原因を排除できていれば、少なくともSendGridから送信されているメールの内容は送信者の意図通りかつ、RFCに則った**一般的には正しい形式のメール**となっているはずです。一般的に正しい形式のメールが送信されているか確認するためには、[メールのソースを確認できる宛先](https://support.google.com/mail/answer/29436?hl=ja)に送ってメールのソースを確認するのがお勧めです。メールのソースの読み方については[ググる](https://www.google.co.jp/search?sourceid=chrome-psyapi2&ion=1&espv=2&ie=UTF-8&q=%E3%83%A1%E3%83%BC%E3%83%AB%20%E3%82%BD%E3%83%BC%E3%82%B9%20%E8%A6%8B%E6%96%B9&oq=%E3%83%A1%E3%83%BC%E3%83%AB%20%E3%82%BD%E3%83%BC%E3%82%B9%20%E8%A6%8B%E6%96%B9&aqs=chrome..69i57j0.4609j0j7)と色々出てくるでしょう。

## 受信側に原因があるケース
これでも文字化けする場合は、リレーしている宛先サーバもしくは、メールを閲覧している受信クライアントに原因があると考えられます。

### 受信クライアントにおける表示形式の不一致
例えば、UTF-8のメールをISO-2022-JPとして解釈して表示している、といった状況です。受信クライアントが自動判定してくれなかったり、デフォルトの表示形式と異なる形式のメールを表示した際に不一致による文字化けが発生します。**そのメールに合った表示形式に切り替えることで解消します**。ただし、受信者への依頼が必要となるため、色々な事情で困難な場合があります。受信者からメールを返信してもらい、X-Mailerヘッダから受信者のクライアントの種類を特定し、具体的な表示形式の切替方法を指示してあげることで比較的スムーズに解決できる可能性があります。

### 受信クライアントにメールを正しく表示する機能がない
例えば、受信クライアントにUTF-8のメールを表示する機能がない、指定されたフォントがインストールされていない、といった状況です。以下のような対処が必要になります。

- 相手が読める形式で送る（送信側で解決を試みる）
- 受信クライアントを変えてもらう、フォントをインストールしてもらうなど（受信側で解決を試みる）

# さいごに
実は、Click Trackingの話を除けばよくある文字化け問題の切り分け手順ではないかと思います。UTF-8だから文字化けしやすい／しにくいとか、ISO-2022-JPだから安全、とかいう単純な話ではなく、

- 送信者が意図通りの内容を送信できているか？
- 送信者が意図した内容を受信側で解釈できているか？

といったあたりがポイントかと思います。ただ、受信側に原因がある場合、解決は困難な場合が多いでしょう。特に受信者がうちのオヤジのような（エンコードとか言っても話が通じない）場合はその傾向が強いと思います。UTF-8の普及により文字化けするケースはだいぶ減ってきているような気はしますが、原因はよくわからないけど受信側で正しく表示されるまで色々な形式で送ってみて試行錯誤する、という闇は当面なくならないのではないかと感じます。