DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

SmtpClientでメールを送信しようとするとFormatExceptionが発生する問題の解決法

SmtpClientクラスを使ってメールを送信する」で紹介したように、SmtpClientクラスを使用すると簡単にSMTPでメールを送信することができます。しかし、送信者や宛先などに指定したメールアドレスによっては、SmtpClientクラスで送信しようとすると例外FormatExceptionがスローされることがあります。これは、MailAddressクラスが事前にメールアドレスをチェックして、RFCに基づいた正式な規則に従っていないメールアドレスが指定された時にFormatExceptionをスローしているためです(詳しくは、「メールアドレスが正式な規則にあっているか検証する」)。しかし規則に違反しているメールアドレスも実在しており、普通に使用されています。このようなメールアドレスにメールを送信できないのは、不便です。

この問題の解決法は、正攻法では、存在しません。よって、「SMTPでメールを送信する」で紹介しているSmtpMailクラスを使用したり、「Socketを使ってSMTPでメールを送信する」のように自分でメールを送信するコードを書いたり、サードパーティーのライブラリを使用するといった解決法になってしまいます。

しかし、強引な方法でもよければ、「Can I turn off the email address validation in System.Net.Mail?」で解決法が紹介されています。この方法によると、非公開のMailAddressコンストラクタ「MailAddress(String, String, String)」をリフレクションで呼び出せば、例外を発生させずにMailAddressオブジェクトを作成できるということです。

しかし、本来はできないことを強引に行っているため、予期せぬトラブルが発生する危険は十分あると思ってください。

この方法でMailAddressオブジェクトを作成する例を示します。SmtpClientクラスでメールを送信する時、メールアドレスを文字列で指定せずに、このように作成したMailAddressオブジェクトを使用するようにしてください。

VB.NET
コードを隠すコードを選択
''' <summary>
''' MailAddressオブジェクトを作成する
''' </summary>
''' <param name="address">メールアドレス。</param>
''' <param name="displayName">表示名。省略する時は、Nothing。</param>
''' <returns>MailAddressオブジェクト</returns>
Public Shared Function CreateMailAddress( _
    address As String, displayName As String) As System.Net.Mail.MailAddress

    If displayName Is Nothing Then
        displayName = String.Empty
    End If

    'メールアドレスをユーザーとホストに分解する
    '(ユーザー名に@が含まれることは考慮していない)
    Dim ss As String() = address.Split(New Char() {"@"c}, 2)

    'MailAddressオブジェクトを作成する
    Return DirectCast( _
        GetType(System.Net.Mail.MailAddress).InvokeMember( _
            Nothing, _
            System.Reflection.BindingFlags.CreateInstance Or _
            System.Reflection.BindingFlags.NonPublic Or _
            System.Reflection.BindingFlags.Instance, _
            Nothing, _
            Nothing, _
            New Object() {displayName, ss(0), ss(1)}),  _
        System.Net.Mail.MailAddress)
End Function
C#
コードを隠すコードを選択
/// <summary>
/// MailAddressオブジェクトを作成する
/// </summary>
/// <param name="address">メールアドレス。</param>
/// <param name="displayName">表示名。省略する時は、null。</param>
/// <returns>MailAddressオブジェクト</returns>
public static System.Net.Mail.MailAddress CreateMailAddress(
    string address, string displayName)
{
    if (displayName == null)
    {
        displayName = string.Empty;
    }

    //メールアドレスをユーザーとホストに分解する
    //(ユーザー名に@が含まれることは考慮していない)
    string[] ss = address.Split(new char[] { '@' }, 2);

    //MailAddressオブジェクトを作成する
    return (System.Net.Mail.MailAddress)
        typeof(System.Net.Mail.MailAddress).InvokeMember(
            null,
            System.Reflection.BindingFlags.CreateInstance |
            System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Instance,
            null,
            null,
            new object[] { displayName, ss[0], ss[1] });
}

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • .NET Tipsをご利用いただく際は、注意事項をお守りください。