Azureはじめました

Windows Azureで業務システムを組んでみる日記

RFC違反のEmailAddressを許容するEmailAddressAttributeを作る

.Netが標準で用意しているEmailAddressAttribute(System.ComponentModel.DataAnnotations)で本来は必要十分なんだが、Docomoauの過去の遺産であるRFC違反アドレスは今もまだ使用されており、ひょんなことからコイツが現れてエラーを巻き起こす。

NTTドコモが新規に取得できるiモードメールにおけるメールアドレスをRFC準拠に変更したとのことです。これまでNTTドコモiモードメールおよびauEZWebにおけるメールアドレスがRFCに準拠していない「.(ピリオド)」の連続利用などができていましたが,iモードメールにおける新規取得分についてはそれらを変更して,RFC準拠としたということです。とここまで書いたけど,mopera Uも大丈夫ですよね?と思ったけど大丈夫っぽいのかな。@の前の.の話がないけど。auも注意が書いてあるから後追いするかな。過去に取得したアドレスが対応しないとという話もありますが,徐々に減っていくでしょうしね。

NTTドコモがメールアドレスをRFC準拠に変更!各社のメールアドレスをまとめてみた | memn0ck.com

NTTドコモは、4月より携帯電話のメールアドレスについて、ルールの変更を行った。  4月1日以降、メールアドレスを新規取得または変更する場合、新ルールが適用される。新ルールでは「○○..○○@docomo.ne.jp」(連続するピリオド)、「○○.@docomo.ne.jp」(@マーク直前のピリオド)といった命名方法が使用不可となる。すでに取得済みのアドレスについては、新ルールは適用されない。

NTTドコモ、メールアドレスのルールを変更 〜 ピリオド連続などが使用不可に | RBB TODAY

こんなのに対応するのはバッドノウハウみたいなもんで不毛きわまりないんだけど、生きてるものは仕方無いからこれをチェックできるように改変する。

元となるソースから拝借

EmailAddressAttribute.cs *1
(記事執筆時点)

namespace System.ComponentModel.DataAnnotations {
    using System;
    using System.ComponentModel.DataAnnotations.Resources;
    using System.Text.RegularExpressions;
 
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public sealed class EmailAddressAttribute : DataTypeAttribute {
 
        // This attribute provides server-side email validation equivalent to jquery validate,
        // and therefore shares the same regular expression.  See unit tests for examples.
        private static Regex _regex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
 
        public EmailAddressAttribute()
            : base(DataType.EmailAddress) {
            ErrorMessage = DataAnnotationsResources.EmailAddressAttribute_Invalid;
        }
 
        public override bool IsValid(object value) {
            if (value == null) {
                return true;
            }
 
            string valueAsString = value as string;
            return valueAsString != null && _regex.Match(valueAsString).Length > 0;
        }
    }
}

素直に正規表現でチェックしているだけみたいだ。

改修

namespace MyNamespace {
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Resources;
    using System.Text.RegularExpressions;
 
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public sealed class EmailAddressJPAttribute : DataTypeAttribute {
 
        // This attribute provides server-side email validation equivalent to jquery validate,
        // and therefore shares the same regular expression.  See unit tests for examples.
        private static Regex _regex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([\.a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
 
        public EmailAddressAttribute()
            : base(DataType.EmailAddress) {
            ErrorMessage = "正しいE-Mailアドレスではありません。";
        }
 
        public override bool IsValid(object value) {
            if (value == null) {
                return true;
            }
 
            string valueAsString = value as string;
            return valueAsString != null && _regex.Match(valueAsString).Length > 0;
        }
    }
}
  • 正規表現でアドレス内のドットの後に許される文字リストにドットを加えた。(連続ドット許可、@直前のドット許可)
  • ErrorMessageの参照先がinternal class (System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources)だったので固定のメッセージに変更

あたり。


Docomoは早くこの違反アドレス回収してくれんかね(;´д`)

*1:オープンソースさまさまである