RFC 2047とは?メールの件名に日本語が使える仕組みをNode.jsの実装とあわせて解説

目次

RFCとは

RFC(Request for Comments)は、インターネット技術の仕様をまとめた文書群です。HTTP、TCP/IP、メールなど、インターネットの根幹をなす技術の多くがRFCとして公開されています。

もともとは技術者同士が意見交換するための文書でしたが、現在ではインターネット標準を定義する正式な仕様書として機能しています。

メール関連で特に重要なRFCは以下の通りです。

RFC内容
RFC 5322メールフォーマット
RFC 2045〜2049MIME仕様
RFC 2047メールヘッダーの文字エンコード
RFC 2616HTTP/1.1(現在は廃止)

本記事で解説するRFC 2047は、メールヘッダー内で日本語などの非ASCII文字を扱うための仕様です。

RFC 2047が必要になった背景

初期の電子メールはASCII文字のみを扱う前提で設計されていました。ASCIIで表現できるのは英数字、記号、一部の制御文字に限られます。

つまり、以下のような日本語の件名はそのままメールヘッダーに記載できませんでした。

お問い合わせありがとうございます

現在では何の変哲もない件名ですが、メールの仕様上、ヘッダーにはASCII文字しか書けないというルールがあったのです。

ASCII制約の具体的な問題

メールヘッダーのSubjectフィールドは、RFC 5322によって7ビットASCIIの範囲内で記述することが求められています。日本語のようなマルチバイト文字をそのまま入れると、中継するメールサーバーが正しく処理できず、文字化けや配送エラーの原因になります。

この問題を解決するために登場したのがRFC 2047です。RFC 2047は、ASCII以外の文字列をASCIIのみの表現に変換して送信するための仕組みを定義しています。

RFC 2047の形式

RFC 2047では、以下のフォーマットを使って非ASCII文字を表現します。

=?charset?encoding?encoded-text?=

各要素の意味は以下の通りです。

項目説明
charset文字コード(例:UTF-8、ISO-2022-JP)
encodingエンコード方式(BまたはQ)
encoded-text変換後の文字列

実際の例を見てみます。

=?UTF-8?B?44GT44KT44Gr44Gh44Gv?=

この文字列は受信側に対して、「UTF-8で符号化され、Base64でエンコードされたデータである」ことを伝えています。受信側はこの情報をもとに正しくデコードし、元の日本語テキストを復元できます。

RFC 2047の構造を図で理解する

=?UTF-8?B?44GT44KT44Gr44Gh44Gv?= UTF-8 B 44GT44KT44Gr44Gh44Gv 文字コード エンコード方式 変換済みデータ 受信側はこの3つの情報をもとにデコードする

RFC 2047は、文字コードとエンコード方式を明示することで、受信側が正しく元のテキストを復元できる仕組みになっています。

エンコード方式:BとQ

RFC 2047のencodingパートには、以下の2種類が利用されます。

記号意味特徴
BBase64任意のバイト列を効率的にASCII化できる。日本語で主流
QQuoted-PrintableASCII文字が多い場合に効率的。欧文で主流

日本語のメールではBase64(B)が使われるケースが圧倒的に多いです。日本語はASCII外の文字がほとんどを占めるため、Quoted-Printableだと逆に冗長になってしまうためです。

エンコードとデコードの基本

エンコードとは、ある形式のデータを別の形式に変換することです。逆の操作がデコードです。

用語意味
エンコード(符号化)データを別の形式に変換する
デコード(復号)元の形式に戻す

RFC 2047におけるBase64エンコードの場合、変換は可逆的です。

こんにちは → 44GT44KT44Gr44Gh44Gv → こんにちは

情報そのものは失われず、表現形式が変わっているだけです。

Base64エンコードの処理フロー

RFC 2047でBase64を利用する場合、内部的には以下の段階を経ています。

  1. 日本語文字列をUTF-8のバイト列に変換する
  2. バイト列をBase64でエンコードする
  3. RFC 2047の形式に組み立てる

お問い合わせありがとうございます UTF-8 バイト列に変換 Base64 エンコード =?UTF-8?B?44GK5ZWP44GE5ZCI44KP44Gb…?= 元の文字列 文字コード 変換方式 完成形 Base64は「変換方式」であり「文字コード」ではない

ここで重要なのは、Base64は文字コードではないという点です。UTF-8が文字コード、Base64はあくまで変換方式(エンコーディング)です。この区別を混同すると、デコード時に誤った手順を踏んでしまう原因になります。

Node.jsでRFC 2047形式を作る

Node.jsではBufferを使うことで、RFC 2047形式の文字列を簡潔に生成できます。

const subject = 'お問い合わせありがとうございます';

const encodedSubject =
  `=?UTF-8?B?${Buffer.from(subject).toString('base64')}?=`;

console.log(encodedSubject);

このコードの中で起きていることを順に見ていきます。

Buffer.from() による文字列のバイト列変換

Buffer.from()は文字列をバイト列に変換します。第2引数を省略した場合、デフォルトでUTF-8として処理されます。

const buf = Buffer.from('こんにちは');
// <Buffer e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af>

BufferはNode.jsが提供するバイナリデータのコンテナです。文字列をバイト列として扱うための中間表現だと考えてください。

toString(‘base64’) によるBase64変換

BuffertoString('base64')を呼ぶと、バイト列がBase64文字列に変換されます。

Buffer.from('こんにちは').toString('base64');
// '44GT44KT44Gr44Gh44Gv'

この結果はASCII文字のみで構成されているため、メールヘッダーに安全に埋め込めます。

RFC 2047形式への組み立て

テンプレートリテラルで=?UTF-8?B??=で囲めば完成です。

const text = 'こんにちは';
const encoded = `=?UTF-8?B?${Buffer.from(text).toString('base64')}?=`;
// =?UTF-8?B?44GT44KT44Gr44Gh44Gv?=

受信側のメールクライアントはこのフォーマットを解析し、UTF-8 + Base64でデコードして元の日本語テキストを復元します。

RFC 2047のラベルが必要な理由

仮にBase64文字列だけを送信した場合を考えてみます。

44GT44KT44Gr44Gh44Gv

受信側はこの文字列を見ただけでは、以下の情報が判断できません。

  • 文字コードがUTF-8なのかShift_JISなのか
  • エンコード方式がBase64なのかQuoted-Printableなのか

文字コードを間違えれば文字化けし、エンコード方式を間違えればデコード自体が失敗します。

RFC 2047のフォーマットは、変換済みデータと一緒に「どう変換したか」のメタ情報を送ることで、受信側に正しいデコード手順を伝えています。つまりRFC 2047は単なるBase64の仕様ではなく、「受信側にデコード方法を伝えるためのラベル付きフォーマット」です。

実務で遭遇しやすい注意点

エンコード済み文字列の長さ制限

RFC 2047では、エンコードされた1つの「encoded-word」は75文字以内に収める必要があります。長い件名の場合は複数のencoded-wordに分割し、それぞれを折り返して連結します。

Subject: =?UTF-8?B?44GK5ZWP44GE5ZCI44KP44Gb?=
 =?UTF-8?B?44GC44KK44GM44Go44GG44GU?=
 =?UTF-8?B?44GE44G+44GZ?=

隣接するencoded-word間の空白とCRLFは、デコード時に無視される仕様です。

ISO-2022-JPとの使い分け

日本語メールの文字コードには、UTF-8のほかにISO-2022-JPが長く使われてきました。古いメールシステムとの互換性が必要な場合はISO-2022-JPを使うこともあります。

=?ISO-2022-JP?B?GyRCJDMkcyRLJEEkTxsoQg==?=

現在はUTF-8が主流になりつつありますが、送信先のメールクライアントによっては文字化けする可能性があるため、利用環境に応じた選択が求められます。

nodemailerを使う場合

実務でNode.jsからメールを送信する場合は、nodemailerのようなライブラリを使うのが一般的です。nodemailerは件名の日本語をRFC 2047に自動で変換してくれるため、通常は手動でエンコードする必要はありません。

const transporter = nodemailer.createTransport({ /* ... */ });

await transporter.sendMail({
  to: 'example@example.com',
  subject: 'お問い合わせありがとうございます', // 自動でRFC 2047に変換される
  text: '本文',
});

ただし、自前でSMTP通信を実装する場合やデバッグ時には、RFC 2047の仕組みを理解しておくことが重要です。文字化けの原因調査でメールヘッダーの生データを読む場面では、この知識が直接役立ちます。

スレッド情報

https://datatracker.ietf.org/doc/html/rfc5322#section-3.6.4

References ヘッダーと In-Reply-To ヘッダーは、RFC 2822 標準に準拠して設定する必要があります。
https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.messages?hl=ja

クライアント スレッド管理方法
Gmail threadId(独自)
Outlook conversationId(独自)
Thunderbird等の従来型クライアント In-Reply-To / Referencesヘッダー(RFC 2822準拠)
In-Reply-To / References が実際に必要になるのは、RFC 2822のヘッダーだけでスレッドを判断する 従来型のメールクライアント の場合です。

Gmail・Outlookのような主要サービスはそれぞれ独自のスレッド管理を持っているので、ヘッダーがなくても動くケースが多いです。ただRFC 2822の標準に準拠しておくという意味で付けている、という方が正確ですね。

参考URL

目次