こんにちはフロントエンドエンジニアのまさにょんです!
今回は、JavaScriptでRFC違反ではないメールアドレスの構造とバリデーション実装方法について解説していきます。
目次
JavaScriptでRFC違反ではないメールアドレスの構造とバリデーション実装方法
メールアドレスの構造を理解する
メールアドレスは、@
より前の「ローカル部分」(local part)と、@
より後の「ドメイン部分」(domain part)の2つのパーツに分けられます。
つまり「 ローカル部分@ドメイン部分 」という構造でできています。
また、ローカル部分は、ユーザー名やアカウント名などとも呼ばれ、メールアドレスを一意に識別するための重要な役割を果たします。
次のメールアドレスは、robotama
がローカル部分、gmail.com
がドメイン部分です。
ローカル部分@ドメイン部分
robotama@gmail.com
RFC違反メールアドレス とは?
RFC違反メールアドレスとは、電子メールアドレスがインターネットの標準的な仕様であるRFC(Request for Comments)に準拠していないことを指します。
RFCは、インターネットのプロトコルや規格などを定める文書であり、
RFCに準拠していない電子メールアドレスは、インターネット上で正しく処理されない可能性があります。
例えば、RFC違反のメールアドレスとしては、ドメイン部分が無効であったり、ローカル部分に不正な文字が含まれていたりする場合があります。
RFC違反メールアドレスを使用すると、メールが正しく配信されなかったり、迷惑メールとして処理されたりする可能性があります。
なので、正しい形式のメールアドレスを使用することが重要です。
RFC準拠でないとメールアドレスの登録ができないWebサイトなどもあります。
RFCに基づくメールアドレスの仕様
RFCに基づくメールアドレスの仕様をまとめると、次のようになります。
最大文字数
ローカル部分、ドメイン部分、「ローカル部分@ドメイン部分」の全体で、それぞれ最大文字数が決まっています。
- ローカル部分は、最大64文字。
- ドメイン部分は、最大253文字。
- ローカル部分@ドメイン部分の全体では、最大254文字。
ローカル部分に使える文字の種類
メールアドレスで、全角文字は使えません。すべて半角になります。
ローカル部分に使える文字の種類の一覧は、
RFC 5322 & 5321に沿ったメールアドレス(local-part)に使える文字まとめ から引用します。
引用元: RFC 5322 & 5321に沿ったメールアドレス(local-part)に使える文字まとめ
- 無条件で使える: 81文字
- アルファベット(大文字 & 小文字)52文字 → A~Z, a~z
- 数字10文字 → 0~9
- 記号19文字 →
!
#
$
%
&
'
*
+
-
/
=
?
^
_
`
{
|
}
~
- 先頭と末尾以外、かつ連続しなければ使える(末尾=
@
の直前): 1文字
- ドット →
.
- ダブルクオートでくくると使える: 93文字
- 無条件で使えるもの81文字
- ドット(連続しよう可) →
.
- 記号10文字 →
(
)
,
:
;
<
>
@
[
]
- ダブルクオートでくくる & バックスラッシュをつけると使える: 97文字
- ダブルクオートでくくると使えるもの93文字
- バックスラッシュと連続すると使える4文字(最後の2つは半角スペースとタブです) →
"
\
タブ
RFC違反メールアドレスのバリデーション実装の要件定義
今回のRFC違反ではないメールアドレスのバリデーション実装の要件定義は、次のとおりです。
次のようなNGパターンのメールアドレスは、RFC違反としてバリデーションでErrorとします。
@
の前のローカル部分で、64文字以上になっている。- ドメイン名が255文字以上の長さになっている。
- メールアドレス全体で256文字以上になっている。
.
(ドット)が、ローカル部分で、2つ以上連続している。.
(ドット)を、ローカル部分の最初と最後(@の直前)に使っている。-
(ハイフン)が、ローカル部分の先頭または末尾にある。-
(ハイフン)が、ドメイン名の一番最後にある。- ドメイン名が数字だけで構成されている。
- ユーザー名またはドメイン名に、RFCに定義されていない特殊文字が含まれている。
(
)
,
:
;
<
>
@
[
]
RFC違反メールアドレスのバリデーション実装のSampleCode
RFC違反メールアドレスのバリデーション実装のSampleCodeは、次のとおりです。
function validateEmail(email) {
// メールアドレス全体で256文字以上になっている
if (256 <= email.length) {
return false;
}
// ローカル部分とドメイン名に分割
const [local, domain] = email.split("@");
// @が含まれていない場合は無効なメールアドレス
if (!domain) {
return false;
}
// ローカル部分で、64文字以上になっている
if (64 <= local.length) {
return false;
}
// ドメイン名が255文字以上の長さになっている
if (255 <= domain.length) {
return false;
}
// .(ドット)が、ローカル部分で、2つ以上連続している
if (local.match(/\.{2,}/)) {
return false;
}
// .(ドット)を、ローカル部分の最初と最後(@の直前)に使っている
if (local.startsWith(".") || local.endsWith(".")) {
return false;
}
// -(ハイフン)が、ローカル部分 or ドメイン部分の先頭または末尾にある
if (
local.startsWith("-") ||
local.endsWith("-") ||
domain.startsWith("-") ||
domain.endsWith("-")
) {
return false;
}
// ドメイン名が数字だけで構成されている
if (domain.match(/^\d+$/)) {
return false;
}
// ユーザー名またはドメイン名に、RFCに定義されていない特殊文字(( ) , : ; < > @ [ ])が含まれている
if (local.match(/[ (),:;<>@[\]]/) || domain.match(/[ (),:;<>@[\]]/)) {
return false;
}
// すべての条件を満たした場合は有効なメールアドレス
return true;
}
// [ 正常系ブロック ]
console.log(validateEmail("robotama@gmail.com")); // true
console.log(validateEmail("robotama@example.co.jp")); // true
console.log(validateEmail("robotama@gmail.com")); // true
console.log(validateEmail("robotama-name@gmail.com")); // true
console.log(validateEmail("robotama.name@gmail.com")); // true
console.log("-------------------------------------------------------");
// [ Validate_Errorブロック ]
// ローカル部分: 64文字
let localLongMail =
"robotamarobotamarobotamarobotamarobotamarobotamarobotamarobotama@gmail.com";
console.log(validateEmail(localLongMail)); // false
console.log(validateEmail("robotama")); // false
console.log(validateEmail("..robotama@gmail.com")); // false
console.log(validateEmail("robotama..puru@gmail.com")); // false
console.log(validateEmail(".robotama@gmail.com")); // false
console.log(validateEmail("robotama.@gmail.com")); // false
console.log(validateEmail("robotama@gmail.com-")); // false
console.log(validateEmail("-robotama@gmail.com")); // false
console.log(validateEmail("robotama-@gmail.com")); // false
console.log(validateEmail("robotama@12345")); // false
console.log(validateEmail("robo[]tama@gmail.com")); // false
console.log(validateEmail("robo<tama@gmail.com")); // false
console.log(validateEmail("robo,tama@gmail.com")); // false
RFC違反メールアドレスのバリデーション実装のSample (Error_MSGバージョン)
次のSampleCodeは、RFC違反メールアドレスのバリデーション実装のError_Messageを表示するためのバージョンです。
// RFC違反_メールアドレス・バリデーション => false: 成功, Error_MSG: 失敗
export function validatRfcEmail(email: string) {
// メールアドレス全体で256文字以上になっている
if (256 <= email.length) {
return 'メールアドレス全体で256文字以上になっています';
}
// ローカル部分とドメイン名に分割
const [local, domain] = email.split('@');
// @が含まれていない場合は無効なメールアドレス
if (!domain) {
return '@が含まれていない場合は無効なメールアドレスです';
}
// ローカル部分で、64文字以上になっている
if (64 <= local.length) {
return '@より前の部分が、64文字以上になっています';
}
// ドメイン名が255文字以上の長さになっている
if (255 <= domain.length) {
return '@より後の部分が255文字以上の長さになっています';
}
// .(ドット)が、ローカル部分で、2つ以上連続している
if (local.match(/\.{2,}/)) {
return '.(ドット)が、@より前の部分で、2つ以上連続しています';
}
// .(ドット)を、ローカル部分の最初と最後(@の直前)に使っている
if (local.startsWith('.') || local.endsWith('.')) {
return '.(ドット)を、ローカル部分の最初と最後(@の直前)に使っています';
}
// -(ハイフン)が、ローカル部分 or ドメイン部分の先頭または末尾にある
if (
local.startsWith('-') ||
local.endsWith('-') ||
domain.startsWith('-') ||
domain.endsWith('-')
) {
return '-(ハイフン)が先頭・末尾または、@の前後にあります';
}
// ドメイン名が数字だけで構成されている
if (domain.match(/^\d+$/)) {
return '@より後の部分が、数字だけで構成されています';
}
// ユーザー名またはドメイン名に、RFCに定義されていない特殊文字(( ) , : ; < > @ [ ])が含まれている
if (local.match(/[ (),:;<>@[\]]/) || domain.match(/[ (),:;<>@[\]]/)) {
return 'RFCに定義されていない特殊文字(( ) , : ; < > @ [ ])が含まれています';
}
// すべての条件を満たした場合は有効なメールアドレス
return false;
}
JavaScript書籍 Ver. 中級-上級者向け
JavaScript書籍 Ver. 初級者向け
Twitterやってます!Follow Me!
神聖グンマー帝国の逆襲🔥
神聖グンマー帝国の科学は、世界一ぃぃぃぃぃぃ!!!!!
参考・引用
- RFC 5322 & 5321に沿ったメールアドレス(local-part)に使える文字まとめ
- 使用可能なメールアドレスについて(RFC準拠)
- 特殊な形式のアドレス(RFC違反アドレス)のご利用について