Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17090] ファイルの概要

このコミットは、Go言語の標準ライブラリであるnet/mailパッケージにおけるメールアドレスのパースに関するバグ修正です。具体的には、メールアドレスの表示名(display name)部分にドット(.)が含まれる場合に、AddressList関数が正しくアドレスを解析できない問題に対処しています。

コミット

commit 73b8baa1bdd76e0e5d898243c9d1d4ee2e6268e3
Author: Ryan Slade <ryanslade@gmail.com>
Date:   Thu Aug 8 10:00:24 2013 -0700

    net/mail: AddressList fails to parse addresses with a dot
    
    Fixes #4938.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/12657044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/73b8baa1bdd76e0e5d898243c9d1d4ee2e6268e3

元コミット内容

このコミットの元の内容は、net/mailパッケージがメールアドレスの表示名にドットを含む場合に解析に失敗するというバグを修正するものです。具体的には、consumeAtom関数の呼び出しにおいて、permissiveフラグをtrueに設定することで、より柔軟な解析を可能にしています。また、この修正を検証するためのテストケースが追加されています。

変更の背景

この変更は、GoのIssue #4938「net/mail: AddressList fails to parse addresses with a dot」に対応するものです。この問題は、net/mailパッケージがメールアドレスの「atom」部分(通常、表示名やローカルパートの一部)に、先頭、末尾、または連続したドットが含まれる場合に、正しく解析できないというものでした。RFC 5322などのメールアドレスの仕様では、これらのドットの使用には特定の制限がありますが、現実世界のメールアドレスには、これらの制限に厳密に従わない形式も存在します。特に、表示名のような人間が読みやすい部分では、より緩やかな解釈が求められることがあります。このバグにより、一部の有効なメールアドレスがGoのnet/mailパッケージで処理できないという問題が発生していました。

前提知識の解説

  • RFC 5322 (Internet Message Format): インターネットメールメッセージの標準フォーマットを定義するRFC(Request For Comments)文書です。メールアドレスの構文、ヘッダーフィールド、メッセージ本文の構造などが規定されています。メールアドレスの「atom」や「quoted-string」などの要素に関するルールも含まれます。
  • メールアドレスの構文: 一般的なメールアドレスはlocal-part@domainの形式を取ります。
    • local-part: @記号の前の部分。ユーザー名などを表します。
    • domain: @記号の後の部分。メールサーバーのドメイン名を表します。
    • display name (表示名): メールアドレスの前に付加される、人間が読みやすい名前(例: John Doe <john.doe@example.com>John Doe部分)。RFCでは、表示名も特定の構文規則に従う必要があります。
  • net/mailパッケージ: Go言語の標準ライブラリの一部で、RFC 5322に準拠したメールメッセージの解析と生成を行うための機能を提供します。ParseAddressParseAddressListなどの関数が含まれます。
  • atomquoted-string: RFC 5322におけるメールアドレスの構文要素です。
    • atom: 特殊文字を含まない連続した文字のシーケンス。例えば、john.doejohndoeはatomになりえます。
    • quoted-string: ダブルクォーテーションで囲まれた文字列。内部に特殊文字を含むことができます。例えば、"John Doe"はquoted-stringです。
  • addrParser: net/mailパッケージ内部で使用される、メールアドレスの文字列を解析するための構造体です。このパーサーが、入力文字列をatomquoted-stringなどの要素に分解していきます。
  • consumeAtom関数: addrParserのメソッドの一つで、入力ストリームからatomを消費(解析し、読み進める)する役割を担います。この関数が、ドットの扱いに厳密すぎたために問題を引き起こしていました。

技術的詳細

このコミットの核心は、net/mailパッケージ内のaddrParser構造体のconsumePhraseメソッドにおけるconsumeAtom関数の呼び出し方法の変更です。

元のコードでは、consumePhraseメソッド内で、メールアドレスの表示名の一部を解析する際に、consumeAtom(false)と呼び出していました。ここで渡されるfalseは、consumeAtom関数が「厳密な」モードで動作することを意味していました。厳密なモードでは、RFC 5322の規定に従い、atomの先頭、末尾、または連続したドットを許可しません。

しかし、Issue #4938で報告されたように、Asem H. <noreply@example.com>のような表示名(Asem H.の部分)は、RFCの厳密な解釈では問題があるかもしれませんが、現実には広く使われています。特に、表示名のような人間が読みやすい部分では、より柔軟な解析が望ましい場合があります。

このコミットでは、consumeAtom(false)consumeAtom(true)に変更しています。trueを渡すことで、consumeAtom関数は「許容的な(permissive)」モードで動作するようになります。許容的なモードでは、atom内のドットの配置に関する一部の厳密なルールが緩和され、先頭、末尾、または連続したドットが含まれていても解析が失敗しなくなります。これにより、Asem H.のような表示名も正しく解析できるようになります。

この変更は、net/mailパッケージがRFCの精神を尊重しつつも、現実世界の多様なメールアドレス形式に対応するためのバランスを取るものです。特に、表示名のようなユーザーフレンドリーな部分では、厳密な構文チェックよりも実用性が優先されることがあります。

コアとなるコードの変更箇所

変更は以下の2つのファイルにわたります。

  1. src/pkg/net/mail/message.go:

    • func (p *addrParser) consumePhrase() (phrase string, err error) メソッド内のp.consumeAtom(false)p.consumeAtom(true)に変更されました。
  2. src/pkg/net/mail/message_test.go:

    • TestAddressParsing関数に、ドットを含む表示名を持つメールアドレスの新しいテストケースが追加されました。具体的には、Asem H. <noreply@example.com>という形式のアドレスが正しく解析されることを確認するテストです。
--- a/src/pkg/net/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -342,7 +342,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			word, err = p.consumeQuotedString()
 		} else {
 			// atom
-			word, err = p.consumeAtom(false)
+			word, err = p.consumeAtom(true)
 		}
 
 		// RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
diff --git a/src/pkg/net/mail/message_test.go b/src/pkg/net/mail/message_test.go
index 2e746f4a72..3c037f3838 100644
--- a/src/pkg/net/mail/message_test.go
+++ b/src/pkg/net/mail/message_test.go
@@ -225,6 +225,16 @@ func TestAddressParsing(t *testing.T) {
 				},
 			},
 		},
+		// Custom example with "." in name. For issue 4938
+		{
+			`Asem H. <noreply@example.com>`,
+			[]*Address{
+				{
+					Name:    `Asem H.`,
+					Address: "noreply@example.com",
+				},
+			},
+		},
 	}
 	for _, test := range tests {
 		if len(test.exp) == 1 {

コアとなるコードの解説

  • src/pkg/net/mail/message.goの変更:

    • consumePhrase関数は、メールアドレスの表示名(例: John Doe)を解析する際に使用されます。表示名は、atom(例: John)の連続、またはquoted-string(例: "John Doe")で構成されます。
    • 変更前のp.consumeAtom(false)は、atomを解析する際にRFCの厳密なルールを適用していました。これにより、Asem H.のように名前にドットが含まれる場合に、そのドットがRFCのatomのルールに違反すると判断され、解析エラーが発生していました。
    • 変更後のp.consumeAtom(true)は、consumeAtom関数に「許容的な」モードで動作するよう指示します。このモードでは、atom内のドットの配置に関する一部の厳密なチェックが緩和されます。これにより、Asem H.のような表示名もエラーなく解析できるようになり、より多くの現実世界のメールアドレス形式に対応できるようになります。
  • src/pkg/net/mail/message_test.goの変更:

    • 追加されたテストケースは、Asem H. <noreply@example.com>という文字列が、Name: "Asem H."Address: "noreply@example.com"を持つAddress構造体として正しく解析されることを検証します。
    • このテストケースは、まさにIssue #4938で報告された問題のシナリオを再現し、修正が正しく機能していることを確認するためのものです。テストが追加されることで、将来の回帰を防ぎ、コードの堅牢性を高めます。

この変更は、net/mailパッケージがRFCの仕様に準拠しつつも、実用的な観点から柔軟性を持たせるための重要な調整と言えます。

関連リンク

参考にした情報源リンク

  • Go Issue #4938のGitHubページ
  • Goのソースコード(src/pkg/net/mail/message.goおよびsrc/pkg/net/mail/message_test.go
  • RFC 5322 (Internet Message Format) - 特にメールアドレスの構文に関するセクション
  • Go 1.2 リリースノート (関連する変更が言及されている可能性)
  • Goのnet/mailパッケージのドキュメント