検索
連載

電子メールを送信するには?(MailKit編)[.NET 4.5、C#/VB].NET TIPS

これまで広く使われてきたSmtpClientクラスは現在、使用が推奨されていない。そこでオープンソースライブラリのMailKitでメールを送信する方法を説明する。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「.NET TIPS」のインデックス

連載「.NET TIPS」

 .NET Framework 2.0以来、メール送信にはSystem.Net.Mail名前空間のSmtpClientクラスが使われてきた。ところが.NET Framework 4.5からは、サードパーティー製のMailKitライブラリが推奨されるようになっている。本稿では、MailKitを使ってメールを送信する方法を解説する。

POINT MailKitでメールを送信する方法

MailKitでメールを送信する方法まとめ
MailKitでメールを送信する方法まとめ


 特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。

 なお、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2017以降が必要である。サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。

using System;
using System.Text;
using static System.Console;

Imports System.Console
Imports System.Text

本稿のサンプルコードに必要な宣言(上:C#、下:VB)

MailKitを使う理由とは?

 従来のSmtpClientクラス(System.Net.Mail名前空間)が「obsoleted(廃止)」扱いとなり、代わりにMailKitを使うように推奨されている。SmtpClientクラスの最新のドキュメントには、次の画像のような記載がある。

SmtpClientのドキュメント(docs.microsoft)
SmtpClientのドキュメント(docs.microsoft)
2017年4月ごろから、"SmtpClient and its network of types are poorly designed"(設計が貧弱である)と記載され、代わりにMailKitとMimeKitを使うように勧められている。
なお、NuGetからMailKitを導入すると自動的にMimeKitも入るので、本稿では「MailKitとMimeKitを使う」というべきところを省略して「MailKitを使う」と書く。

 また、実際にも、本稿で解説するようにMailKitはとても使いやすい。MailKitが対応している.NET Framwork 4.5以降であれば、SmtpClientではなくMailKitを使うべきである。

 MailKitは、次の3つのメールクライアントAPIを提供している。

  • SMTPクライアント
  • POP3クライアント
  • IMAP4クライアント

 MailKitを使えば、メール送信だけでなく、メール受信とIMAPサーバ上でのメール管理も行えるのである。本稿ではSMTPクライアントの使い方だけを紹介するので、詳しくはMailKitのドキュメントをご覧いただきたい。

 MailKitは、プラットフォームも広くカバーしている。対応している主なプラットフォームには次のようなものがある。

  • .NET Framework 4.5以降
  • .NET Standard 1.3以降(=.NET Core 1.0以降/UWP 10.0.12040以降)
  • Xamarin.Android/Xamarin.iOS

 MailKitはオープンソースのライブラリであり、そのソースコードはGitHubで公開されている。ライセンスはMITライセンスである。ライセンスを見ると、著作権はXamarin社(2016年からMicrosoftの子会社)になっている。

MailKitを導入するには?

 ソースコードをダウンロードして自分でビルドしても構わないが、通常はNuGetからプロジェクトに導入すればよい。

 Visual StudioのNuGetパッケージ管理画面で「MailKit」を検索してインストールする(次の画像)。

NuGetでMailKitを検索する(Visual Studio 2017)
NuGetでMailKitを検索する(Visual Studio 2017)

テキストメールを送信するには?

 MimeMessageクラス(MimeKit名前空間)のオブジェクトを作って宛先や本文などをセットし、SmtpClientクラス(MailKit.Net.Smtp名前空間)を使ってそれを送信する。

 SMTPサーバのユーザー認証に使うユーザー名とパスワードを引数として受け取るメソッドにまとめると、次のコードのようになる。宛先やSMTPサーバ名などを「***」で伏せ字にしているが、実際には適切な文字列を設定していただきたい(以降も同様)。

static async void SendMailAsync(string userName, string password)
{
  // MimeMessageを作り、宛先やタイトルなどを設定する
  var message = new MimeKit.MimeMessage();
  message.From.Add(new MimeKit.MailboxAddress("MailKit ユーザー", "***@***.com"));
  message.To.Add(new MimeKit.MailboxAddress("MailKit 試験", "***@***.jp"));
  // message.Cc.Add(……省略……);
  // message.Bcc.Add(……省略……);
  message.Subject = "MailKit でメールを送信するテスト";

  // 本文を作る
  var textPart = new MimeKit.TextPart(MimeKit.Text.TextFormat.Plain);
  textPart.Text = @"MailKit を使ってメールを送ってみるテストです。";

  // MimeMessageを完成させる
  message.Body = textPart;

  // SMTPサーバに接続してメールを送信する
  using (var client = new MailKit.Net.Smtp.SmtpClient())
  {
#if DEBUG
    // 開発用のSMTPサーバが暗号化に対応していないときは、次の行を追加する
    //client.ServerCertificateValidationCallback = (s, c, h, e) => true;
#endif

    try
    {
      await client.ConnectAsync("smtp.***.com", 587);
      WriteLine("接続完了");

      // SMTPサーバがユーザー認証を必要としない場合は、次の2行は不要
      await client.AuthenticateAsync(userName, password);
      WriteLine("認証完了");

      await client.SendAsync(message);
      WriteLine("送信完了");

      await client.DisconnectAsync(true);
      WriteLine("切断");
    }
    catch (Exception ex)
    {
      WriteLine(ex.ToString());
    }
  }
}

Async Sub SendMailAsync(userName As String, password As String)
  ' MimeMessageを作り、宛先やタイトルなどを設定する
  Dim message = New MimeKit.MimeMessage()
  message.From.Add(New MimeKit.MailboxAddress("MailKit ユーザー", "***@***.com"))
  message.To.Add(New MimeKit.MailboxAddress("MailKit 試験", "***@***.jp"))
  ' message.Cc.Add(……省略……)
  ' message.Bcc.Add(……省略……)
  message.Subject = "MailKit でメールを送信するテスト"

  ' 本文を作る
  Dim textPart = New MimeKit.TextPart(MimeKit.Text.TextFormat.Plain)
  textPart.Text = "MailKit を使ってメールを送ってみるテストです。"

  ' MimeMessageを完成させる
  message.Body = textPart

  ' SMTPサーバに接続してメールを送信する
  Using client = New MailKit.Net.Smtp.SmtpClient()
#If DEBUG Then
    ' 開発用のSMTPサーバが暗号化に対応していないときは、次の行を追加する
    ' client.ServerCertificateValidationCallback = Function(s, c, h, e) True
#End If

    Try
      Await client.ConnectAsync("smtp.***.com", 587)
      WriteLine("接続完了")

      ' SMTPサーバがユーザー認証を必要としない場合は、次の2行は不要
      Await client.AuthenticateAsync(userName, password)
      WriteLine("認証完了")

      Await client.SendAsync(message)
      WriteLine("送信完了")

      Await client.DisconnectAsync(True)
      WriteLine("切断")

    Catch ex As Exception
      WriteLine(ex.ToString())
    End Try
  End Using
End Sub

プレーンテキストのメールを送信するメソッドの例(上:C#、下:VB)
宛先などはAddメソッドで追加するようになっている。ここでは1人ずつしか設定していないが、複数指定したければAddメソッドを繰り返せばよい。
ここではSMTPサーバとの通信に非同期バージョンのメソッドを使っているが、同期バージョンのメソッド(メソッド名の末尾に「Async」が付かないもの)も用意されている。
ConnectAsyncメソッドの第2引数で587番ポートを指定しているが、これはSTARTTLSである。SMTPS(SMTP over SSL/TLS)を使うなら465番ポート、暗号化なしで通信するなら25番ポートを指定する。
SMTPサーバとの接続や通信中にエラーがあった場合は例外が発生するので、適切にキャッチする。

 上のコードでは、宛先や本文などにわざと日本語を入れている。これで問題なくメールが届く。ただし、UTF-8でエンコードされる。

宛名や本文をJISコードで送るには?

 最近は、UTF-8のメールを表示できないメールクライアントアプリはほとんど見かけなくなった。それでも旧製品を使い続けているエンドユーザーに配慮して、JISコードでエンコーディングしておきたいこともあるだろう。

 宛名などをJISコードで送るには、MailboxAddressクラス(MimeKit名前空間)のコンストラクタ引数にEncodingオブジェクト(System.Text名前空間)を与える(次のコード)。

// message.To.Add(new MimeKit.MailboxAddress("MailKit 試験", "***@***.jp"));
// ↓
var jis = Encoding.GetEncoding("iso-2022-jp");
message.To.Add(new MimeKit.MailboxAddress(jis, "MailKit 試験", "***@*.com"));

' message.To.Add(New MimeKit.MailboxAddress("MailKit 試験", "***@***.jp"))
' ↓
Dim jis = Encoding.GetEncoding("iso-2022-jp")
message.To.Add(New MimeKit.MailboxAddress(jis, "MailKit 試験", "***@***.com"))

宛先をJISコードでエンコーディングさせる例(上:C#、下:VB)

 本文をJISコードにするには、TextPartオブジェクト(MimeKit名前空間)に本文をセットするときに、TextプロパティではなくSetTextメソッドを使う。こちらは、Encodingオブジェクトを渡してもよいが、エンコーディング名でも構わない(次のコード)。

//textPart.Text = @"MailKit を使ってメールを送ってみるテストです。";
// ↓
textPart.SetText("iso-2022-jp",
                  @"MailKit を使ってメールを送ってみるテストです。");

'textPart.Text = "MailKit を使ってメールを送ってみるテストです。"
' ↓
textPart.SetText("iso-2022-jp",
                  "MailKit を使ってメールを送ってみるテストです。")

本文をJISコードでエンコーディングさせる例(上:C#、下:VB)

ファイルを添付するには?

 前述したテキストの本文だけを送信する場合には、MimeMessageオブジェクトのBodyプロパティにTextPartオブジェクトをセットした。

 ファイルを添付する場合は、ファイルからMimePartオブジェクト(MimeKit名前空間)を作り、本文のTextPartオブジェクトと合わせてMultipartオブジェクト(MimeKit名前空間)に格納し、それをMimeMessageオブジェクトのBodyプロパティにセットする(次のコード)。

//message.Body = textPart;
// ↓
var path = @"C:\Windows\Web\Wallpaper\Theme2\img10.jpg"; // 添付したいファイル
var attachment = new MimeKit.MimePart("image", "jpeg")
{
  Content = new MimeKit.MimeContent(System.IO.File.OpenRead(path)),
  ContentDisposition = new MimeKit.ContentDisposition(),
  ContentTransferEncoding = MimeKit.ContentEncoding.Base64,
  FileName = System.IO.Path.GetFileName(path)
};

var multipart = new MimeKit.Multipart("mixed");
multipart.Add(textPart);
multipart.Add(attachment);

message.Body = multipart;

'message.Body = textPart
' ↓
Dim path = "C:\Windows\Web\Wallpaper\Theme2\img10.jpg" '添付したいファイル
Dim attachment = New MimeKit.MimePart("image", "jpeg") _
With {
  .Content = New MimeKit.MimeContent(System.IO.File.OpenRead(path)),
  .ContentDisposition = New MimeKit.ContentDisposition(),
  .ContentTransferEncoding = MimeKit.ContentEncoding.Base64,
  .FileName = System.IO.Path.GetFileName(path)
}

Dim multipart = New MimeKit.Multipart("mixed")
multipart.Add(textPart)
multipart.Add(attachment)

message.Body = multipart

ファイルを添付する例(上:C#、下:VB)
添付ファイルのパスは、適切なものに修正してほしい。

まとめ

 メールを送信するには、従来のSmtpClientクラスに代わってサードパーティー製のMailKitライブラリが推奨されるようになった。MailKitは本稿で紹介したように簡単に使える上に、高機能である。

利用可能バージョン:.NET Framework 4.5以降
カテゴリ:オープンソースライブラリ 処理対象:Windowsフォーム
カテゴリ:オープンソースライブラリ 処理対象:WPF
カテゴリ:オープンソースライブラリ 処理対象:Xamarin.Forms
カテゴリ:クラスライブラリ 処理対象:電子メール
使用ライブラリ:MimeMessageクラス(MimeKit名前空間)
使用ライブラリ:SmtpClientクラス(MailKit.Net.Smtp名前空間)
関連TIPS:構文:インスタンス化と同時にプロパティを設定するには?[C#/VB]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]


「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

ページトップに戻る