DOBON.NET

SmtpClientクラスを使ってメールを送信する

注意:ここで紹介しているコードを実際に使用する場合は、必ずSMTPサーバー、送信者、宛先などの設定を適切に変更してください。

ここでは、.NET Framework 2.0からサポートされたSmtpClientクラスを使ってSMTPでメールを送信する基本的な方法を紹介します。なお、添付ファイル、HTMLメール、SMTP認証、SSL/TLSなどについては別のページで説明していますので、「インターネット編メニュー」をご覧ください。

.NET Framework 1.1以前でメールを送信する方法は、「SMTPでメールを送信する」をご覧ください。

最も簡単な方法

まずは、最も簡単であろう例を示します。

VB.NET
コードを隠すコードを選択
'送信者
Dim senderMail As String = "sender@xxx.xxx"
'宛先
Dim recipientMail As String = "recipient@xxx.xxx"
'件名
Dim subject As String = "こんにちは"
'本文
Dim body As String = "こんにちは。" + vbCrLf + vbCrLf + "それではまた。"

'SmtpClientオブジェクトを作成する
Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーを指定する
sc.Host = "localhost"
'ポート番号を指定する(既定値は25)
sc.Port = 25
'メールを送信する
sc.Send(senderMail, recipientMail, subject, body)
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//送信者
string senderMail = "sender@xxx.xxx";
//宛先
string recipientMail = "recipient@xxx.xxx";
//件名
string subject = "こんにちは";
//本文
string body = "こんにちは。\r\n\r\nそれではまた。";

//SmtpClientオブジェクトを作成する
System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーを指定する
sc.Host = "localhost";
//ポート番号を指定する(既定値は25)
sc.Port = 25;
//SMTPサーバーに送信する設定にする(既定はNetwork)
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メールを送信する
sc.Send(senderMail, recipientMail, subject, body);
//後始末(.NET Framework 4.0以降)
sc.Dispose();

上記のような方法で送信されたメールは、件名、本文ともに、文字コードUTF-8のBase64でエンコードされて送信されます(ただしアルファベットのみの場合は、件名はそのままで、本文はUS-ASCIIのQuoted-Printable)。具体的には、上記のコードでは、以下のように送信されます。

mime-version: 1.0
from: sender@xxx.xxx
to: recipient@xxx.xxx
date: 20 Jan 2007 22:05:18 +0900
subject: =?utf-8?B?44GT44KT44Gr44Gh44Gv?=
content-type: text/plain; charset=utf-8
content-transfer-encoding: base64

44GT44KT44Gr44Gh44Gv44CCDQoNCuOBneOCjOOBp+OBr+OBvuOBn+OAgg==

.

MailMessageクラスを使用してメールを送信する

上記の方法ではSmtpClientクラスだけでメールを送信していましたが、今度はMailMessageオブジェクトを作成して、メールの送信に使用する方法を紹介します。

下の例では、FromとToに、メールアドレスのほかに、名前も指定しています。

VB.NET
コードを隠すコードを選択
'MailMessageの作成
Dim msg As New System.Net.Mail.MailMessage()
'送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = New System.Net.Mail.MailAddress("sender@xxx.xxx", "鈴木")
'宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(New System.Net.Mail.MailAddress("recipient@xxx.xxx", "加藤"))
'件名
msg.Subject = "こんにちは"
'本文
msg.Body = "こんにちは。" + vbCrLf + vbCrLf + "それではまた。"

Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//MailMessageの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
//送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = new System.Net.Mail.MailAddress("sender@xxx.xxx", "鈴木");
//宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(new System.Net.Mail.MailAddress("recipient@xxx.xxx", "加藤"));
//件名
msg.Subject = "こんにちは";
//本文
msg.Body = "こんにちは。\r\n\r\nそれではまた。";

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
//後始末(.NET Framework 4.0以降)
sc.Dispose();

このように送信者、宛先に名前を指定したとき、これらはUTF-8 + Quoted-Printableでエンコードされます。

上記のメールは、具体的には次のように送信されます。

mime-version: 1.0
from: =?utf-8?Q?=E9=88=B4=E6=9C=A8?= <sender@xxx.xxx>
to: =?utf-8?Q?=E5=8A=A0=E8=97=A4?= <recipient@xxx.xxx>
date: 20 Jan 2007 22:23:05 +0900
subject: =?utf-8?B?44GT44KT44Gr44Gh44Gv?=
content-type: text/plain; charset=utf-8
content-transfer-encoding: base64

44GT44KT44Gr44Gh44Gv44CCCgrjgZ3jgozjgafjga/jgb7jgZ/jgII=

.

文字コードを指定してメールを送信する

UTF-8以外の文字コードでメールを送信する場合は、文字コードを指定する必要があります。メールの件名と本文の文字コードは、MailMessageクラスのSubjectEncodingBodyEncodingプロパティに指定します。送信者やあて先の名前の文字コードは、MailAddressのコンストラクタの3番目の引数に指定します。

以下に、JISコードを指定する例を示します。Encodingについて詳しくは、「文字コードを指定してテキストファイルを読み込む」をご覧ください。

VB.NET
コードを隠すコードを選択
'JISコード
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(50220)

'メッセージの作成
Dim msg As New System.Net.Mail.MailMessage()
'件名と本文の文字コードを指定する
msg.SubjectEncoding = enc
msg.BodyEncoding = enc
'送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = New System.Net.Mail.MailAddress("sender@xxx.xxx", "鈴木", enc)
'宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(New System.Net.Mail.MailAddress("recipient@xxx.xxx", "加藤", enc))
'件名
msg.Subject = "こんにちは"
'本文
msg.Body = "こんにちは。" + vbCrLf + vbCrLf + "それではまた。"

Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//JISコード
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(50220);

//メッセージの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
//件名と本文の文字コードを指定する
msg.SubjectEncoding = enc;
msg.BodyEncoding = enc;
//送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = new System.Net.Mail.MailAddress("sender@xxx.xxx", "鈴木", enc);
//宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(new System.Net.Mail.MailAddress("recipient@xxx.xxx", "加藤", enc));
//件名
msg.Subject = "こんにちは";
//本文
msg.Body = "こんにちは。\r\n\r\nそれではまた。";

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
//後始末(.NET Framework 4.0以降)
sc.Dispose();

上記のコードを実行したときにSMTPサーバーに送信されるデータは、以下のようになります。

mime-version: 1.0
from: "=?iso-2022-jp?Q?=1B$BNkLZ=1B(B?=" <sender@xxx.xxx>
to: "=?iso-2022-jp?Q?=1B$B2CF#=1B(B?=" <recipient@xxx.xxx>
date: 20 Jan 2007 22:23:05 +0900
subject: =?iso-2022-jp?Q?=1B$B$3$s$K$A$O=1B(B?=
content-type: text/plain; charset=iso-2022-jp
content-transfer-encoding: quoted-printable

=1B$B$3$s$K$A$O!#=1B(B=0A=0A=1B$B$=3D$l$G$O$^$?!#=1B(B

.

これを見ていただければ分かるとおり、すべてQuoted-Printableでエンコードされます。

ヘッダをBase64でエンコードする

まずは、件名や送信者、あて先の名前をQuoted-Printableではなく、Base64でエンコードする方法を紹介します。これには、自分でエンコードを行い、MailMessageにはEncodingを指定しないで、そのまま送信するようにします。

以下に例を示します。まず、次のようなメソッドを作成します。

VB.NET
コードを隠すコードを選択
''' <summary>
''' メッセージヘッダのためのRFC2047形式の文字列に変換する(Base64)
''' </summary>
''' <param name="str">変換もとの文字列</param>
''' <param name="enc">エンコーディング</param>
''' <returns></returns>
Private Function EncodeMailHeader(ByVal str As String, _
        ByVal enc As System.Text.Encoding) As String
    'Base64でエンコードする
    Dim ret As String = System.Convert.ToBase64String(enc.GetBytes(str))
    'RFC2047形式に
    ret = String.Format("=?{0}?B?{1}?=", enc.BodyName, ret)
    Return ret
End Function
C#
コードを隠すコードを選択
/// <summary>
/// メッセージヘッダのためのRFC2047形式の文字列に変換する(Base64)
/// </summary>
/// <param name="str">変換もとの文字列</param>
/// <param name="enc">エンコーディング</param>
/// <returns></returns>
private string EncodeMailHeader(string str, System.Text.Encoding enc)
{
    //Base64でエンコードする
    string ret = System.Convert.ToBase64String(enc.GetBytes(str));
    //RFC2047形式に
    ret = string.Format("=?{0}?B?{1}?=", enc.BodyName, ret);
    return ret;
}

このメソッドを利用して、次のようにメールを送信します。

VB.NET
コードを隠すコードを選択
'JISコード
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(50220)

'メッセージの作成
Dim msg As New System.Net.Mail.MailMessage()
'件名と本文の文字コードを指定する
'送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = New System.Net.Mail.MailAddress( _
    "sender@xxx.xxx", EncodeMailHeader("""鈴木""", enc))
'宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(New System.Net.Mail.MailAddress( _
    "recipient@xxx.xxx", EncodeMailHeader("""加藤""", enc)))
'件名
msg.Subject = EncodeMailHeader("こんにちは", enc)
'本文
msg.Body = "こんにちは。" + vbCrLf + vbCrLf + "それではまた。"

Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//JISコード
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(50220);

//メッセージの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
//件名と本文の文字コードを指定する
//送信者(メールアドレスが"sender@xxx.xxx"、名前が"鈴木"の場合)
msg.From = new System.Net.Mail.MailAddress(
    "sender@xxx.xxx", EncodeMailHeader("\"鈴木\"", enc));
//宛先(メールアドレスが"recipient@xxx.xxx"、名前が"加藤"の場合)
msg.To.Add(new System.Net.Mail.MailAddress(
    "recipient@xxx.xxx", EncodeMailHeader("\"加藤\"", enc)));
//件名
msg.Subject = EncodeMailHeader("こんにちは", enc);
//本文
msg.Body = "こんにちは。\r\n\r\nそれではまた。";

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
//後始末(.NET Framework 4.0以降)
sc.Dispose();

この方法で送信されるデータは、次のようになります。

mime-version: 1.0
from: =?iso-2022-jp?B?GyRCTmtMWhsoQg==?= <sender@xxx.xxx>
to: =?iso-2022-jp?B?GyRCMkNGIxsoQg==?= <recipient@xxx.xxx>
date: 20 Jan 2007 22:23:05 +0900
subject: =?iso-2022-jp?B?GyRCJDMkcyRLJEEkTxsoQg==?=
content-type: text/plain; charset=utf-8
content-transfer-encoding: base64

44GT44KT44Gr44Gh44Gv44CCCgrjgZ3jgozjgafjga/jgb7jgZ/jgII=

.

「content-transfer-encoding: 7bit」で送信する

.NET Framework 4.5からは、MailMessage.BodyTransferEncodingプロパティを「SevenBit」にすることで、「content-transfer-encoding: 7bit」で送信することができます。

VB.NET
コードを隠すコードを選択
'JISコード
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(50220)

'MailMessageの作成
Dim msg As New System.Net.Mail.MailMessage("from@xxx.xxx", "to@xxx.xxx")
msg.Subject = "題名"
msg.SubjectEncoding = enc
'本文と、本文の文字コードを設定する
msg.Body = "こんにちは。"
msg.BodyEncoding = enc
'「content-transfer-encoding」を「7bit」にする
msg.BodyTransferEncoding = System.Net.Mime.TransferEncoding.SevenBit

Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
sc.Dispose()
C#
コードを隠すコードを選択
//JISコード
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(50220);

//MailMessageの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage(
    "from@xxx.xxx", "to@xxx.xxx");
msg.Subject = "題名";
msg.SubjectEncoding = enc;
//本文と、本文の文字コードを設定する
msg.Body = "こんにちは。";
msg.BodyEncoding = enc;
//「content-transfer-encoding」を「7bit」にする
msg.BodyTransferEncoding = System.Net.Mime.TransferEncoding.SevenBit;

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
sc.Dispose();

これで送信されるデータは、以下のようになります。

MIME-Version: 1.0
From: from@xxx.xxx
To: to@xxx.xxx
Date: 25 Jun 2013 01:24:40 +0900
Subject: =?iso-2022-jp?Q?=1B=24BBjL=3E=1B=28B?=
Content-Type: text/plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit

こんにちは。

.

.NET Framework 4.0未満の場合は、おがわみつぎさんのこちらの記事で、「限りなく完全に近い」という方法が紹介されています。これはAlternateViewを使うという方法で、次のような感じです。

VB.NET
コードを隠すコードを選択
'JISコード
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(50220)

'MailMessageの作成
Dim msg As New System.Net.Mail.MailMessage("from@xxx.xxx", "to@xxx.xxx")
msg.Subject = "題名"
msg.SubjectEncoding = enc

'プレーンテキストのAlternateViewを作成
Dim htmlView As System.Net.Mail.AlternateView = _
    System.Net.Mail.AlternateView.CreateAlternateViewFromString( _
        "こんにちは。", enc, System.Net.Mime.MediaTypeNames.Text.Plain)
'TransferEncoding.SevenBitを指定
htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.SevenBit
'AlternateViewを追加
msg.AlternateViews.Add(htmlView)

Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//JISコード
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(50220);

//MailMessageの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage(
    "from@xxx.xxx", "to@xxx.xxx");
msg.Subject = "題名";
msg.SubjectEncoding = enc;

//プレーンテキストのAlternateViewを作成
System.Net.Mail.AlternateView htmlView =
    System.Net.Mail.AlternateView.CreateAlternateViewFromString(
        "こんにちは。",
        enc,
        System.Net.Mime.MediaTypeNames.Text.Plain);
//TransferEncoding.SevenBitを指定
htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.SevenBit;
//AlternateViewを追加
msg.AlternateViews.Add(htmlView);

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
//後始末(.NET Framework 4.0以降)
sc.Dispose();

.NET Framework 2.0の場合、これで送信されるデータは、次のようなものです。

mime-version: 1.0
from: from@xxx.xxx
to: to@xxx.xxx
date: 23 Jan 2007 01:21:43 +0900
subject: =?iso-2022-jp?Q?=1B$BBjL>=1B(B?=
content-type: text/plain; charset=iso-2022-jp
content-transfer-encoding: sevenbit

こんにちは。

.

"Content-Transfer-Encoding"が"7bit"ではなく"sevenbit"になっていますが、この問題はすでに修正されています。詳しくは、「FIX: The value of the TransferEncoding property may be incorrect when you run a Visual Studio 2005 program that uses the System.Net.Mime or System.Net.Mail namespaces」をご覧ください。(コメントにてご報告いただきました。)

タイムアウトする時間を設定する

Sendメソッドは同期的にメールを送信するため、Sendメソッドを呼び出すと、その処理がすべて終了するまでブロックされます。送信の処理が思ったよりずっと長くかかってしまうと困る場合は、SmtpClient.Timeoutプロパティでタイムアウトする時間を指定することができます。時間はミリ秒で指定し、デフォルトは100000ミリ秒(100秒)です。

VB.NET
コードを隠すコードを選択
Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーなどを設定する
sc.Host = "localhost"
sc.Port = 25
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
'タイムアウトする時間を1分に設定する
sc.Timeout = 60000
'メールを送信する
sc.Send("a@xxx.xxx", "b@xxx.xxx", "題名", "本文")
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーなどを設定する
sc.Host = "localhost";
sc.Port = 25;
sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
//タイムアウトする時間を1分に設定する
sc.Timeout = 60000;
//メールを送信する
sc.Send("a@xxx.xxx", "b@xxx.xxx", "題名", "本文");
//後始末(.NET Framework 4.0以降)
sc.Dispose();

非同期的にメールを送信する

SmtpClient.SendAsyncメソッドにより、非同期的にメールを送信することもできます。非同期的な送信では、送信に時間のかかるような場合でも、アプリケーションがフリーズしたように固まることがなくなります。

SendAsyncメソッドで非同期送信を行うと、SendAsyncCancelメソッドでその処理を途中でキャンセルできます。送信が完了すれば、SendCompletedイベントが発生します。

以下に非同期的にメールを送信する例を示します。ここでは、Button1をクリックすることによりメールの送信を開始し、送信が終了すると完了のメッセージが表示されます。Button2をクリックすることにより、送信を途中でキャンセルできます。

VB.NET
コードを隠すコードを選択
'SmtpClientオブジェクト
Dim sc As System.Net.Mail.SmtpClient = Nothing

'Button1のClickイベントハンドラ
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _
        Handles Button1.Click
    Button1.Enabled = False
    Button2.Enabled = True

    'MailMessageの作成
    Dim msg As New System.Net.Mail.MailMessage( _
        "sender@xxx.xxx", "recipient@xxx.xxx", "題名", "本文")

    'SmtpClientの作成
    If sc Is Nothing Then
        sc = New System.Net.Mail.SmtpClient()
        'イベントハンドラの追加
        AddHandler sc.SendCompleted, AddressOf sc_SendCompleted
    End If
    'SMTPサーバーなどを設定する
    sc.Host = "localhost"
    sc.Port = 25
    sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
    'メールを送信する
    'MailMessageをSendCompletedイベントハンドラで取得できるようにする
    sc.SendAsync(msg, msg)
End Sub

'Button2のClickイベントハンドラ
Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) _
        Handles Button2.Click
    'メールの送信をキャンセルする
    If Not (sc Is Nothing) Then
        sc.SendAsyncCancel()
    End If
End Sub

'メール送信が完了したとき
Private Sub sc_SendCompleted(ByVal sender As Object, _
        ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
    'SendAsyncで指定されたMailMessageを取得する
    Dim msg As System.Net.Mail.MailMessage = _
        CType(e.UserState, System.Net.Mail.MailMessage)

    If e.Cancelled Then
        Console.WriteLine("[{0}]の送信はキャンセルされました。", msg.Subject)
    Else
        If Not (e.Error Is Nothing) Then
            Console.WriteLine("[{0}]の送信でエラーが発生しました。", msg.Subject)
            Console.WriteLine(e.Error.Message)
        Else
            Console.WriteLine("[{0}]の送信が完了しました。", msg.Subject)
        End If
    End If
    '後始末
    msg.Dispose()

    Button1.Enabled = True
    Button2.Enabled = False
End Sub
C#
コードを隠すコードを選択
//SmtpClientオブジェクト
System.Net.Mail.SmtpClient sc = null;

//Button1のClickイベントハンドラ
private void Button1_Click(object sender, EventArgs e)
{
    Button1.Enabled = false;
    Button2.Enabled = true;

    //MailMessageの作成
    System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage(
        "sender@xxx.xxx", "recipient@xxx.xxx", "題名", "本文");

    //SmtpClientの作成
    if (sc == null)
    {
        sc = new System.Net.Mail.SmtpClient();
        //イベントハンドラの追加
        sc.SendCompleted +=
            new System.Net.Mail.SendCompletedEventHandler(sc_SendCompleted);
    }
    //SMTPサーバーなどを設定する
    sc.Host = "localhost";
    sc.Port = 25;
    sc.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
    //メールを送信する
    //MailMessageをSendCompletedイベントハンドラで取得できるようにする
    sc.SendAsync(msg, msg);
}

//Button2のClickイベントハンドラ
private void Button2_Click(object sender, EventArgs e)
{
    //メールの送信をキャンセルする
    if (sc != null)
        sc.SendAsyncCancel();
}

//メール送信が完了したとき
private void sc_SendCompleted(object sender,
       System.ComponentModel.AsyncCompletedEventArgs e)
{
    //SendAsyncで指定されたMailMessageを取得する
    System.Net.Mail.MailMessage msg = (System.Net.Mail.MailMessage)e.UserState;

    if (e.Cancelled)
    {
        Console.WriteLine("[{0}]の送信はキャンセルされました。", msg.Subject);
    }
    else if (e.Error != null)
    {
        Console.WriteLine("[{0}]の送信でエラーが発生しました。", msg.Subject);
        Console.WriteLine(e.Error.Message);
    }
    else
    {
        Console.WriteLine("[{0}]の送信が完了しました。", msg.Subject);
    }

    //後始末
    msg.Dispose();

    Button1.Enabled = true;
    Button2.Enabled = false;
}

なお、非同期送信ではTimeoutプロパティは無視されます。タイムアウトする時間は、自分で実装する必要があります。

アプリケーション構成ファイルに設定を記述する

アプリケーションやコンピュータ構成ファイルに、SMTPサーバー、ポート番号、認証に使用するユーザー名とパスワード、さらに"From"のデフォルトを記述しておくことができます。このようにすると、プログラムでこれらを指定する必要がなくなります。なお、アプリケーション構成ファイルに関しては、こちらをご覧ください。

具体的には、たとえば次のような記述をアプリケーション構成ファイルに追加します。

<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod="Network" from="from@xxx.xxx">
        <network
          host="localhost"
          port="25"
          userName="user"
          password="pass"
        />
      </smtp>
    </mailSettings>
  </system.net>
</configuration>

こうすると、以下のように、From、SMTPサーバー、ユーザー名、パスワードを指定しないでメールを送信することができるようになります。

VB.NET
コードを隠すコードを選択
'MailMessageの作成
Dim msg As New System.Net.Mail.MailMessage()
'宛先
msg.To.Add("recipient@xxx.xxx")
'件名
msg.Subject = "こんにちは"
'本文
msg.Body = "こんにちは。それではまた。"

Dim sc As New System.Net.Mail.SmtpClient()
'メッセージを送信する
sc.Send(msg)

'後始末
msg.Dispose()
'後始末(.NET Framework 4.0以降)
sc.Dispose()
C#
コードを隠すコードを選択
//MailMessageの作成
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
//宛先
msg.To.Add("recipient@xxx.xxx");
//件名
msg.Subject = "こんにちは";
//本文
msg.Body = "こんにちは。\r\n\r\nそれではまた。";

System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//メッセージを送信する
sc.Send(msg);

//後始末
msg.Dispose();
//後始末(.NET Framework 4.0以降)
sc.Dispose();

アプリケーション構成ファイルで指定した値はあくまでデフォルトの値なので、コードで指定した値が優先されます。

また、上記ではdefaultCredentialsを指定しませんでしたが、「defaultCredentials="true"」のように指定することもできます。ただしこの場合、userNameとpasswordは無視されます。

補足:.NET Framework 4.0からは、clientDomain、enableSsl、targetNameの設定もできるようになりました。

アプリケーション構成ファイルの設定を取得する

アプリケーション構成ファイルのmailSettingsに記述されている設定は、次のようにして取得することができます。なお、参照に「System.Configuration.dll」を加える必要があります。

VB.NET
コードを隠すコードを選択
'アプリケーション構成ファイルのmailSettingsの設定を取得
Dim smtpSec As System.Net.Configuration.SmtpSection = _
    CType(System.Configuration.ConfigurationManager.GetSection( _
        "system.net/mailSettings/smtp"), _
        System.Net.Configuration.SmtpSection)

Console.WriteLine("From:{0}", smtpSec.From)
Console.WriteLine("Host:{0}", smtpSec.Network.Host)
Console.WriteLine("Port:{0}", smtpSec.Network.Port)
Console.WriteLine("UserName:{0}", smtpSec.Network.UserName)
Console.WriteLine("Password:{0}", smtpSec.Network.Password)
C#
コードを隠すコードを選択
//アプリケーション構成ファイルのmailSettingsの設定を取得
System.Net.Configuration.SmtpSection smtpSec =
    (System.Net.Configuration.SmtpSection)
    System.Configuration.ConfigurationManager.GetSection(
        "system.net/mailSettings/smtp");

Console.WriteLine("From:{0}", smtpSec.From);
Console.WriteLine("Host:{0}", smtpSec.Network.Host);
Console.WriteLine("Port:{0}", smtpSec.Network.Port);
Console.WriteLine("UserName:{0}", smtpSec.Network.UserName);
Console.WriteLine("Password:{0}", smtpSec.Network.Password);

ASP.NETでは、次のようにします。「System.Configuration.dll」と「System.Web.dll」の参照が必要です。

VB.NET
コードを隠すコードを選択
'Web構成ファイルのmailSettingsの設定を取得
Dim config As System.Configuration.Configuration = _
    System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration( _
        HttpContext.Current.Request.ApplicationPath)
Dim mailSet As System.Net.Configuration.MailSettingsSectionGroup = _
    CType(config.GetSectionGroup("system.net/mailSettings"), _
        System.Net.Configuration.MailSettingsSectionGroup)

Console.WriteLine("From:{0}", mailSet.Smtp.From)
Console.WriteLine("Host:{0}", mailSet.Smtp.Network.Host)
Console.WriteLine("Port:{0}", mailSet.Smtp.Network.Port)
Console.WriteLine("UserName:{0}", mailSet.Smtp.Network.UserName)
Console.WriteLine("Password:{0}", mailSet.Smtp.Network.Password)
C#
コードを隠すコードを選択
//Web構成ファイルのmailSettingsの設定を取得
System.Configuration.Configuration config =
    System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(
        HttpContext.Current.Request.ApplicationPath);
System.Net.Configuration.MailSettingsSectionGroup mailSet =
    (System.Net.Configuration.MailSettingsSectionGroup)
        config.GetSectionGroup("system.net/mailSettings");

Console.WriteLine("From:{0}", mailSet.Smtp.From);
Console.WriteLine("Host:{0}", mailSet.Smtp.Network.Host);
Console.WriteLine("Port:{0}", mailSet.Smtp.Network.Port);
Console.WriteLine("UserName:{0}", mailSet.Smtp.Network.UserName);
Console.WriteLine("Password:{0}", mailSet.Smtp.Network.Password);

または、次のような方法もあります。

VB.NET
コードを隠すコードを選択
'Web構成ファイルのmailSettingsの設定を取得
Dim smtpSec As System.Net.Configuration.SmtpSection = _
    CType( _
    System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection( _
    "system.net/mailSettings/smtp"), System.Net.Configuration.SmtpSection)

Console.WriteLine("From:{0}", smtpSec.From)
Console.WriteLine("Host:{0}", smtpSec.Network.Host)
Console.WriteLine("Port:{0}", smtpSec.Network.Port)
Console.WriteLine("UserName:{0}", smtpSec.Network.UserName)
Console.WriteLine("Password:{0}", smtpSec.Network.Password)
C#
コードを隠すコードを選択
//Web構成ファイルのmailSettingsの設定を取得
System.Net.Configuration.SmtpSection smtpSec =
    (System.Net.Configuration.SmtpSection)
    System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection(
        "system.net/mailSettings/smtp");

Console.WriteLine("From:{0}", smtpSec.From);
Console.WriteLine("Host:{0}", smtpSec.Network.Host);
Console.WriteLine("Port:{0}", smtpSec.Network.Port);
Console.WriteLine("UserName:{0}", smtpSec.Network.UserName);
Console.WriteLine("Password:{0}", smtpSec.Network.Password);

SmtpClientクラスの問題点

上で紹介した以外に、次のような問題もあるようです。

メールがすぐに送信されない

アンチウィルス系のアプリケーションを使用しており、送信されるメールのチェックを行っている場合などでは、SmtpClient.Sendメソッドでメールを送信してもすぐには送信されない場合があるようです。この解決法は、「Delayed send with smtpclient in .net 2.0」で紹介されています。これによると、SmtpClientのServicePoint.MaxIdleTimeを1にすればよいとのことです(その後の投稿には、1000の方がよいともあります)。

VB.NET
コードを隠すコードを選択
Dim sc As New System.Net.Mail.SmtpClient()
'SMTPサーバーを指定する
sc.Host = "localhost"
'↓を追加
sc.ServicePoint.MaxIdleTime = 1
'メールを送信する
sc.Send("a@xxx.xxx", "b@xxx.xxx", "題名", "本文")
C#
コードを隠すコードを選択
System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient();
//SMTPサーバーを指定する
sc.Host = "localhost";
//↓を追加
sc.ServicePoint.MaxIdleTime = 1;
//メールを送信する
sc.Send("a@xxx.xxx", "b@xxx.xxx", "題名", "本文");

これでもダメならば、アンチウィルスソフトが送信されるメールのチェックをしないように設定してください。

FormatExceptionがスローされ、メールが送信できない

他のメールクライアントでは正常に送信することができるメールアドレスに送信しようとしても、FormatException例外がスローされて送信できないケースがあるようです。この問題については、「SmtpClientでメールを送信しようとするとFormatExceptionが発生する問題の解決法」で詳しく説明します。

  • 履歴:
  • 2013/6/25 .NET Framework 4.0で追加されたSmtpClient.DisposeとMailMessage.BodyTransferEncodingメソッドに関する記述を追加など。
  • 2014/12/17 「FormatExceptionがスローされ、メールが送信できない」を別のページに移動。

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

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • 「???を参照に追加します」の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。
共有する

この記事への評価

この記事へのコメント

この記事に関するコメントを投稿するには、下のボタンをクリックしてください。投稿フォームへ移動します。通常のご質問、ご意見等は掲示板へご投稿ください。