LoginSignup
26
18

こんにちは、そろそろ家の更新時期が迫ってきて引越し先の物件に悩んでいるしっぽくんです。最近業務でメールアドレスについて触れる機会があったので今回はそのお話をしようかと思います。
私自身あまり馴染みのなかった「RFC違反メールアドレス」について深堀っていく記事になりますので、ご興味あればご一読いただけると幸いです。

この記事で触れること

  • RFC違反メールアドレスとはどういうことなのか
  • HTML標準やバリデーションライブラリにおけるメールアドレスについて

違反しているメールアドレス??

さてこの中に仲間外れがあります。どれでしょう?

  1. test.test.@example.com
  2. test.test@example.com
  3. test..test@example.com

正解は2です。これ以外は違反しているメールアドレスです!具体的にどんな違反メールアドレスなのでしょうか?

前置きを踏まえて、私達の日頃の業務の中でお客様からの問い合わせで回答の難しいものが開発チームに回ってくることがあります。弊社のシステムの中でメール送信を扱うものがあり、今回の問い合わせはそれでした。

一口にメールが届かないと言っても原因は様々ありますが、今回の問い合わせはどうやら「RFC違反メールアドレス」というものでした。(ここでは原因の特定には触れません)

:thinking: はて、RFC違反ってなんだ??」

あいにくとメール送信に関する知識は遠い昔の学生時代に触れた程度で、「RFC」という存在も恥ずかしながら知りません。

知らないなら知る機会!

一個ずつ調べてみることにしました。

RFCとは?

全くわからない概念なのでChatGPTさんに聞いてみることに。

「RFCって何?要約して教えて下さい」

RFCとは、"Request for Comments"の略で、インターネット技術に関する文書の標準化プロセスを定義する文書のことです。これは、インターネットのプロトコルや手順に関する提案や仕様を共有し、議論するためのものです。RFCは、インターネット技術の進化と標準化を促進するために広く使用されています。

なるほど、プロトコルを定義しているもの。今回だとメールアドレスのプロトコルが記載されているRFCがあると推察。

「メールアドレスに関するRFCはありますか?」

はい、メールアドレスに関するRFCはいくつか存在します。その中でも代表的なものはRFC5321(Simple Mail Transfer Protocol)とRFC 5322(Internet Message Format)です。これらのRFCは、電子メールの送信や受信に関するプロトコルやフォーマットについて定義しています。

お目当てのものが見つかりました。さてここからはどんな内容が違反になっているのかを調べてみましょう。

余談ですが、日頃触れているフレームワークなどでも採用されています。言われてみると確かに見てましたね…。

RFC5322を追え🏃‍♂

RFC5321はメール送信に関するプロトコルについて書かれているので、フォーマットに関して書かれているRFC5322の特にsection-3#Syntaxを見て正しいメールアドレスのフォーマットを調べてみます。

以降の要約などは自分の解釈に基づいたもののため、一部間違っている可能性があります。
もし間違っている場合は大変勉強になるためご指摘いただけると幸いです。

さて何もわからないので、順番に上から見ていきます。

前提(RFC5234)

The following primitive tokens that are used but otherwise unspecified are taken from the "Core Rules" of [RFC5234], Appendix B.1: CR, LF, CRLF, HTAB, SP, WSP, DQUOTE, DIGIT, ALPHA, and VCHAR.

どうやらRFC5234なるものがでてきました。どうやら独自定義があるようです。しかし見てみると意外とこれまで見聞きしたものがいくつかでてきていますね。

RFC5234#appendix-B.1から引用。
また述べられているものだけピックアップしています。

         ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z

         CR             =  %x0D
                                ; carriage return

         CRLF           =  CR LF
                                ; Internet standard newline

         DIGIT          =  %x30-39
                                ; 0-9

         DQUOTE         =  %x22
                                ; " (Double Quote)

         HTAB           =  %x09
                                ; horizontal tab

         LF             =  %x0A
                                ; linefeed

         SP             =  %x20

         VCHAR          =  %x21-7E
                                ; visible (printing) characters

         WSP            =  SP / HTAB
                                ; white space

In some of the definitions, there will be non-terminals whose names start with "obs-". These "obs-" elements refer to tokens defined in the obsolete syntax in section 4.

廃止された定義もある。

Atom

section 3.2.3では基本となる構成について書かれていました。

Several productions in structured header field bodies are simply strings of certain basic characters. Such productions are called atoms.

atoms と呼ばれる基本構成があるとのこと。先程述べたRFC5234のプリミティブトークンと合わせて使うのでしょうか?

Some of the structured header field bodies also allow the period character (".", ASCII value 46) within runs of atext. An additional "dot-atom" token is defined for those purposes.

atext と呼ばれるものの中に . を許可するものもあり、それを dot-atom と呼ばれるそうです。いよいよわからない単語が増えてきましたね。

ここまででてきたワードを整理している表があったので引用します。

atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
                       "!" / "#" /        ;  characters not including
                       "$" / "%" /        ;  specials.  Used for atoms.
                       "&" / "'" /
                       "*" / "+" /
                       "-" / "/" /
                       "=" / "?" /
                       "^" / "_" /
                       "`" / "{" /
                       "|" / "}" /
                       "~"

   atom            =   [CFWS] 1*atext [CFWS]

   dot-atom-text   =   1*atext *("." 1*atext)

   dot-atom        =   [CFWS] dot-atom-text [CFWS]

   specials        =   "(" / ")" /        ; Special characters that do
                       "<" / ">" /        ;  not appear in atext
                       "[" / "]" /
                       ":" / ";" /
                       "@" / "\" /
                       "," / "." /
                       DQUOTE

上記の表を見ると、RFC5234で出てきたプリミティブトークンと特定の文字を組み合わせて構成されているみたいですね。

atext はアルファベット(A-Z, a-z)と数値(0-9)、!#$%&'*+-/=?^_`{|}~を含むものと定義されています。

dot-atom-text(≒ dot-atom)は 1文字以上のatextを含み、0個以上の.atextで連なったものと定義されています。

Quoted characters & Quoted Strings

section 3.2.1section 3.2.4では少し似たような内容に触れていたので合わせて紹介します。

   quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp

3.2.1のquoted-pairでは \VCHAR もしくはスペースで構成されており、エスケープを意味しています。

   qtext           =   %d33 /             ; Printable US-ASCII
                       %d35-91 /          ;  characters not including
                       %d93-126 /         ;  "\" or the quote character
                       obs-qtext

   qcontent        =   qtext / quoted-pair

   quoted-string   =   [CFWS]
                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE
                       [CFWS]

qtextVCHARから \" を除いたもので構成され、qcontentqtext もしくは quoted-pair によって構成されています。
さらに quoted-string" で囲まれた0個以上の qcontent になっています。

Addr-Spec Specification

section 3.4addr-spec、ついにメールアドレスのフォーマット定義にたどり着きました、長かったです。

   addr-spec       =   local-part "@" domain

addr-spec@ で仕切られたlocal-partdomainに分かれています。

   local-part      =   dot-atom / quoted-string / obs-local-part

   domain          =   dot-atom / domain-literal / obs-domain

更に local-partdot-atom または quoted-string によって構成されています。
今回の主題である「違反しているメールアドレス」はこのlocal-partの定義を紐解けば理解できそうです、燃えてきました。

まとめ

これまでの調べでメールアドレスは local-part @ domain に分かれていることがわかりました。
更に local-partdot-atom もしくは quoted-string によって成り立っています。
dot-atom は 1文字以上の atext(アルファベット(A-Z, a-z)と数値(0-9)、!#$%&'*+-/=?^_`{|}~) を含み、0個以上の.とatextで連なったものと定義されています。

つまり、 . 開始ではなく、. が2つ以上連続していない、 atext に定義されている文字で構成されたものであれば正しいメールアドレスと言えそうです。

ただし quoted-string はこれに該当せず、 "で囲まれた VCHAR(ただし\と"は除く) とエスケープによって構成されているので、基本的には " で囲めばだいたい処理されそうですね。

最後に簡易的なテーブルでまとめてみました。

要素 説明
local-part @ の前の部分
dot-atom もしくは quoted-string で構成
test.test
domain @ の後の部分
dot-atom もしくは domain-literal で構成
example.com
dot-atom 1文字以上の atext を含み、0個以上の.atextで連なったもの test.test
quoted-string " で囲まれた文字列 "test.test"
atext アルファベット(A-Z, a-z)、数値(0-9)、
!#$%&'*+-/=?^_`{|}~を含む文字
test

余談:メールサービスの対応

メールアドレスといえば各キャリアが提供する「キャリアメール」もありますね。
各キャリアでは「RFC違反メールアドレス」をどう扱っているのでしょうか?

RFC違反アドレスに関しては現在ご利用が推奨されていないため、今後メールサービスでの障害が発生する場合があります。

auメール(@au.com/@ezweb.ne.jp)を送信できないことがあります。

メールアプリによってはサポートされていません。

どこも非推奨と書かれています。
しかしながら利用ユーザーは最初に作ったメールアドレスを変更する手間もあるため、非推奨と言えど利用されている現状です。

更に余談:開発視点から見たメールアドレス

メールアドレスと言えばブラウザ上で入力する機会も多いですね。私達が開発しているシステムもそうです。
ではHTMLの仕様ではどう定義されているのでしょうか?

email         = 1*( atext / "." ) "@" label *( "." label )
label         = let-dig [ [ ldh-str ] let-dig ]  ; limited to a length of 63 characters by RFC 1034 section 3.5
atext         = < as defined in RFC 5322 section 3.2.3 >
let-dig       = < as defined in RFC 1034 section 3.5 >
ldh-str       = < as defined in RFC 1034 section 3.5 >

見慣れた文字が存在しますね・・・。
丁寧なことに正規表現も記載されています。

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

しかし先程まで見ていた定義と少し異なり、 local-part が 1個以上の atext もしくは . となっています。
なぜ異なっているのかの理由までは調べきれなかったのですが、今回の問い合わせ同様既に作られているメールアドレスを入力できない状態を避けるためだと思われます。

もういっちょ余談: バリデーションライブラリ

ついでバリデーションライブラリについても調べてみました。

最後に

メールアドレス1つとっても規格は様々で一概にこれでOKということはなさそうですが、送れないケースの1つとして認識しておいたほうがよさそうです。
また非推奨になっているもののまだ利用されているユーザーはいるため、対応の可否が求められそうです。

PR

株式会社HRBrainでは、一緒に働く仲間を募集しています!

26
18
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
18