SMTP認証でメールを送信する.NET Framework 2.0以降で、SmtpClientクラスを使用する方法SmtpClientクラスのCredentialsプロパティを使うことにより、ユーザー名とパスワードを指定してメールを送信することができます。 'MailMessageの作成 Dim msg As New System.Net.Mail.MailMessage( _ "from@xxx.xxx", "to@xxx.xxx", "題名", "本文") Dim sc As New System.Net.Mail.SmtpClient() 'SMTPサーバーを指定する sc.Host = "localhost" 'ユーザー名とパスワードを設定する sc.Credentials = New System.Net.NetworkCredential("user", "pass") '現在は、EnableSslがtrueでは失敗する sc.EnableSsl = False 'Timeoutを指定しないと失敗するとの報告もあるようだが、不明 'sc.Timeout = 100000; 'メッセージを送信する sc.Send(msg) '後始末 msg.Dispose() //MailMessageの作成 System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage( "from@xxx.xxx", "to@xxx.xxx", "題名", "本文"); System.Net.Mail.SmtpClient sc = new System.Net.Mail.SmtpClient(); //SMTPサーバーを指定する sc.Host = "localhost"; //ユーザー名とパスワードを設定する sc.Credentials = new System.Net.NetworkCredential("user", "pass"); //現在は、EnableSslがtrueでは失敗する sc.EnableSsl = false; //Timeoutを指定しないと失敗するとの報告もあるようだが、不明 //sc.Timeout = 100000; //メッセージを送信する sc.Send(msg); //後始末 msg.Dispose(); SSLを使用するにはEnableSslプロパティをtrueにしますが、現在はCredentialsを設定し、EnableSslをtrueにすると、エラーとなるようです。 対応している認証方法は不明ですが、どうやらLOGINには対応しているようです(ご存知の方は、ぜひお知らせください)。
補足:ユーザー名とパスワードのデフォルト値をアプリケーション構成ファイルに記述しておくこともできます。詳しくは、こちらをご覧ください。
MailMessage.Fieldsプロパティを使う方法.NET Framework 1.1からは、MailMessageクラスのFieldsプロパティを使用することにより、System.Web.Mail.SmtpMailクラスでもSMTP認証によるメールの送信ができます。この方法は「The Code Project - SMTP Authentication using System.Web.Mail (CDOSYS)」で紹介されています。 Dim mail As New System.Web.Mail.MailMessage 'From mail.From = "xxx@xxx.xxx" 'To mail.To = "xxx@xxx.xxx" 'Subject mail.Subject = "テスト" '本文 mail.Body = "これはテストです。" 'smtpauthenticateを使う時は必ず2にする mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/sendusing") _ = 2 'sendusingを2にした時は、必ずサーバーとポートを指定する 'SMTPサーバーを指定 mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/smtpserver") _ = "xxx.xxx.xxx" 'ポート番号を指定する mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/smtpserverport") _ = 25 '認証を使う '1はbasic認証、2はNTLM認証 mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1 'ユーザー名 mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/sendusername") _ = "xxx" 'パスワード mail.Fields.Item( _ "http://schemas.microsoft.com/cdo/configuration/sendpassword") _ = "xxx" System.Web.Mail.SmtpMail.SmtpServer = "xxx.xxx.xxx" 'メールを送信 System.Web.Mail.SmtpMail.Send(mail) System.Web.Mail.MailMessage mail = new System.Web.Mail.MailMessage(); //From mail.From = "xxx@xxx.xxx"; //To mail.To = "xxx@xxx.xxx"; //Subject mail.Subject = "テスト"; //本文 mail.Body = "これはテストです。"; //smtpauthenticateを使う時は必ず2にする mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2; //sendusingを2にした時は、必ずサーバーとポートを指定する //SMTPサーバーを指定 mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/smtpserver"] = "xxx.xxx.xxx"; //ポート番号を指定する mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = 25; //認証を使う //1はbasic認証、2はNTLM認証 mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1; //ユーザー名 mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/sendusername"] = "xxx"; //パスワード mail.Fields[ "http://schemas.microsoft.com/cdo/configuration/sendpassword"] = "xxx"; System.Web.Mail.SmtpMail.SmtpServer = "xxx.xxx.xxx"; //メールを送信 System.Web.Mail.SmtpMail.Send(mail); CDOを使えない環境では、この方法は無理です。その場合は、自分でコードを書くか、誰かが作ったコンポーネントやクラスを使わせてもらうかということになるでしょう。 Socketを使ってSMTPでメールを送る方法自分でコードを書くということになると、ソケットを使用することになります。この場合はもちろん、SMTPやMIMEに関する知識が必要です。SMTPについてRFCではRFC821(SIMPLE MAIL TRANSFER PROTOCOL)で、さらにESMTPについてはRFC1869(SMTP Service Extensions)などで定義されています。 ここではソケットを使ってSMTPメール送信するサンプルを示します。しかしこれはあくまでただの簡単なサンプルでしかありませんので、何も理解せずに、このコードをそのまま利用することは絶対にしないでください。RFCを読み気がない、あるいは理解できないという方は、Tatsuo Babaさんの「BASP21 DLL」や市販品をご利用ください。 なおこのクラスの使い方に関しては、エントリポイントのSmtpクラスのMainメソッドを参考にしてください。 Imports System Imports System.Net.Sockets Imports System.Text Imports System.Collections.Specialized Namespace Dobon.Mail ''' <summary> ''' 送信用のメールメッセージ ''' </summary> Public Class SmtpMailMessage Private _from As String ''' <summary> ''' 送信者のメールアドレス ''' </summary> Public Property From() As String Get Return _from End Get Set(ByVal Value As String) _from = Value End Set End Property Private _to As String ''' <summary> ''' 送信先のメールアドレス ''' </summary> Public Property [To]() As String Get Return _to End Get Set(ByVal Value As String) _to = Value End Set End Property Private _subject As String ''' <summary> ''' メールの件名 ''' </summary> Public Property Subject() As String Get Return _subject End Get Set(ByVal Value As String) _subject = Value End Set End Property Private _body As String ''' <summary> ''' メールの本文 ''' </summary> Public Property Body() As String Get Return _body End Get Set(ByVal Value As String) _body = Value End Set End Property End Class ''' <summary> ''' SMTPでメールを送信する ''' </summary> Public Class Smtp ''' <summary> ''' エントリポイント ''' </summary> Public Shared Sub Main() Dim mail As New SmtpMailMessage 'From mail.From = "xxx@xxx.xxx" 'To mail.To = "xxx@xxx.xxx" 'Subject mail.Subject = "テスト" '本文 mail.Body = "これはテストです。" Dim smtp As New Smtp 'SMTPサーバー名 smtp.SmtpServer = "xxx.xxx.xxx" 'ポート番号 smtp.SmtpPort = 25 '認証 smtp.AuthMethod = SmtpAuthMethod.Plain smtp.AuthUserName = "xxxxx" smtp.AuthPassword = "xxxxx" '送信する smtp.Send(mail) Console.ReadLine() End Sub Private _smtpServer As String ''' <summary> ''' SMTPサーバー ''' </summary> Public Property SmtpServer() As String Get Return _smtpServer End Get Set(ByVal Value As String) _smtpServer = Value End Set End Property Private _smtpPort As Integer = 25 ''' <summary> ''' ポート番号 ''' </summary> Public Property SmtpPort() As Integer Get Return _smtpPort End Get Set(ByVal Value As Integer) _smtpPort = Value End Set End Property Private _authUserName As String ''' <summary> ''' 認証で用いるユーザー名 ''' </summary> Public Property AuthUserName() As String Get Return _authUserName End Get Set(ByVal Value As String) _authUserName = Value End Set End Property Private _authPassword As String ''' <summary> ''' 認証で用いるパスワード ''' </summary> Public Property AuthPassword() As String Get Return _authPassword End Get Set(ByVal Value As String) _authPassword = Value End Set End Property ''' <summary> ''' SMTPの認証方法 ''' </summary> Public Enum SmtpAuthMethod None Plain Login End Enum Private _authMethod As SmtpAuthMethod = SmtpAuthMethod.None ''' <summary> ''' 認証方法 ''' </summary> Public Property AuthMethod() As SmtpAuthMethod Get Return _authMethod End Get Set(ByVal Value As SmtpAuthMethod) _authMethod = Value End Set End Property Private _stream As NetworkStream Private _recMsg As String Private boundary As String ''' <summary> ''' メールを送信する ''' </summary> ''' <param name="mail">送信するメール</param> Public Sub Send(ByVal mail As SmtpMailMessage) Dim soc As New TcpClient '接続 soc.Connect(SmtpServer, SmtpPort) _stream = soc.GetStream() Try ReceiveData() If Not _recMsg.StartsWith("220") Then Throw New ApplicationException("接続に失敗しました。") End If SendData("EHLO" + vbCrLf) ReceiveData() If Not _recMsg.StartsWith("250") Then Throw New ApplicationException(_recMsg) End If '認証する If AuthMethod <> SmtpAuthMethod.None Then Authenticate() End If SendData(("MAIL FROM:" + mail.From + vbCrLf)) ReceiveData() If Not _recMsg.StartsWith("250") Then Throw New ApplicationException(_recMsg) End If SendData(("RCPT TO:" + mail.To + vbCrLf)) ReceiveData() If Not _recMsg.StartsWith("250") Then Throw New ApplicationException(_recMsg) End If SendData("DATA" + vbCrLf) ReceiveData() If Not _recMsg.StartsWith("354") Then Throw New ApplicationException(_recMsg) End If '送信データ Dim data As String = "" data += "From: " + mail.From + vbCrLf data += "To: " + mail.To + vbCrLf '件名をBase64でエンコード data += "Subject: =?ISO-2022-JP?B?" + _ GetBase64String(mail.Subject) + "?=" + vbCrLf data += "MIME-Version: 1.0" + vbCrLf data += "Content-Transfer-Encoding: 7bit" + vbCrLf data += "Content-Type: text/plain; charset=ISO-2022-JP" _ + vbCrLf data += vbCrLf + mail.Body.Replace( _ vbCrLf + "." + vbCrLf, vbCrLf + ".." + vbCrLf) _ + vbCrLf data += "." + vbCrLf SendData(data) ReceiveData() SendData("QUIT" + vbCrLf) ReceiveData() Finally '切断する If Not _stream Is Nothing Then _stream.Close() End If soc.Close() End Try End Sub 'データを受信する Private Sub ReceiveData() Dim enc As Encoding = Encoding.GetEncoding(50220) Dim data(1024) As Byte Dim len As Integer Dim str As String = "" Dim ms As New System.IO.MemoryStream 'すべて受信する Do '受信 len = _stream.Read(data, 0, data.Length) ms.Write(data, 0, len) '文字列に変換する str = enc.GetString(ms.ToArray()) Loop While Not str.EndsWith(vbCrLf) OrElse _ System.Text.RegularExpressions.Regex.IsMatch( _ str, "(?:^|\n)\d+-[^\r\n]*\r\n$") ms.Close() '表示 Console.Write(("S: " + str)) _recMsg = str End Sub 'データを送信する Private Sub SendData(ByVal str As String) Dim enc As Encoding = Encoding.GetEncoding(50220) 'byte型配列に変換 Dim data As Byte() = enc.GetBytes(str) '送信 _stream.Write(data, 0, data.Length) '表示 Console.Write(("C: " + str)) End Sub 'JISでエンコードし、Base64に変換 Private Function GetBase64String(ByVal str As String) As String Dim enc As Encoding = Encoding.GetEncoding(50220) Return Convert.ToBase64String(enc.GetBytes(str)) End Function '認証を行う Private Sub Authenticate() If AuthMethod = SmtpAuthMethod.Plain Then 'PLAIN SendData("AUTH PLAIN" + vbCrLf) ReceiveData() If Not _recMsg.StartsWith("334") Then If _recMsg.StartsWith("502") Then '認証の必要なし Return End If Throw New ApplicationException(_recMsg) End If Dim str As String = AuthUserName + _ ControlChars.NullChar + AuthUserName + _ ControlChars.NullChar + AuthPassword SendData((GetBase64String(str) + vbCrLf)) ReceiveData() If Not _recMsg.StartsWith("235") Then Throw New ApplicationException(_recMsg) End If ElseIf AuthMethod = SmtpAuthMethod.Login Then 'LOGIN SendData("AUTH LOGIN" + vbCrLf) ReceiveData() If Not _recMsg.StartsWith("334") Then If _recMsg.StartsWith("502") Then '認証の必要なし Return End If Throw New ApplicationException(_recMsg) End If SendData((GetBase64String(AuthUserName) + vbCrLf)) ReceiveData() If Not _recMsg.StartsWith("334") Then Throw New ApplicationException(_recMsg) End If SendData((GetBase64String(AuthPassword) + vbCrLf)) ReceiveData() If Not _recMsg.StartsWith("235") Then Throw New ApplicationException(_recMsg) End If End If End Sub End Class End Namespace using System; using System.Net.Sockets; using System.Text; using System.Collections.Specialized; namespace Dobon.Mail { /// <summary> /// 送信用のメールメッセージ /// </summary> public class SmtpMailMessage { private string _from; /// <summary> /// 送信者のメールアドレス /// </summary> public string From { get { return _from; } set { _from = value; } } private string _to; /// <summary> /// 送信先のメールアドレス /// </summary> public string To { get { return _to; } set { _to = value; } } private string _subject; /// <summary> /// メールの件名 /// </summary> public string Subject { get { return _subject; } set { _subject = value; } } private string _body; /// <summary> /// メールの本文 /// </summary> public string Body { get { return _body; } set { _body = value; } } } /// <summary> /// SMTPでメールを送信する /// </summary> public class Smtp { /// <summary> /// エントリポイント /// </summary> public static void Main() { SmtpMailMessage mail = new SmtpMailMessage(); //From mail.From = "xxx@xxx.xxx"; //To mail.To = "xxx@xxx.xxx"; //Subject mail.Subject = "テスト"; //本文 mail.Body = "これはテストです。"; Smtp smtp = new Smtp(); //SMTPサーバー名 smtp.SmtpServer = "xxx.xxx.xxx"; //ポート番号 smtp.SmtpPort = 25; //認証 smtp.AuthMethod = SmtpAuthMethod.Plain; smtp.AuthUserName = "xxxxx"; smtp.AuthPassword = "xxxxx"; //送信する smtp.Send(mail); Console.ReadLine(); } private string _smtpServer; /// <summary> /// SMTPサーバー /// </summary> public string SmtpServer { get { return _smtpServer; } set { _smtpServer = value; } } private int _smtpPort = 25; /// <summary> /// ポート番号 /// </summary> public int SmtpPort { get { return _smtpPort; } set { _smtpPort = value; } } private string _authUserName; /// <summary> /// 認証で用いるユーザー名 /// </summary> public string AuthUserName { get { return _authUserName; } set { _authUserName = value; } } private string _authPassword; /// <summary> /// 認証で用いるパスワード /// </summary> public string AuthPassword { get { return _authPassword; } set { _authPassword = value; } } /// <summary> /// SMTPの認証方法 /// </summary> public enum SmtpAuthMethod { None, Plain, Login } private SmtpAuthMethod _authMethod = SmtpAuthMethod.None; /// <summary> /// 認証方法 /// </summary> public SmtpAuthMethod AuthMethod { get { return _authMethod; } set { _authMethod = value; } } private NetworkStream _stream; private string _recMsg; private string boundary; /// <summary> /// メールを送信する /// </summary> /// <param name="mail">送信するメール</param> public void Send(SmtpMailMessage mail) { TcpClient soc = new TcpClient(); //接続 soc.Connect(SmtpServer, SmtpPort); _stream = soc.GetStream(); try { ReceiveData(); if (!_recMsg.StartsWith("220")) throw new ApplicationException("接続に失敗しました。"); SendData("EHLO\r\n"); ReceiveData(); if (!_recMsg.StartsWith("250")) throw new ApplicationException(_recMsg); //認証する if (AuthMethod != SmtpAuthMethod.None) Authenticate(); SendData("MAIL FROM:" + mail.From + "\r\n"); ReceiveData(); if (!_recMsg.StartsWith("250")) throw new ApplicationException(_recMsg); SendData("RCPT TO:" + mail.To + "\r\n"); ReceiveData(); if (!_recMsg.StartsWith("250")) throw new ApplicationException(_recMsg); SendData("DATA\r\n"); ReceiveData(); if (!_recMsg.StartsWith("354")) throw new ApplicationException(_recMsg); //送信データ string data = ""; data += "From: " + mail.From + "\r\n"; data += "To: " + mail.To + "\r\n"; //件名をBase64でエンコード data += "Subject: =?ISO-2022-JP?B?" + GetBase64String(mail.Subject) + "?=" + "\r\n"; data += "MIME-Version: 1.0\r\n"; data += "Content-Transfer-Encoding: 7bit\r\n"; data += "Content-Type: text/plain; charset=ISO-2022-JP\r\n"; data += "\r\n" + mail.Body.Replace("\r\n.\r\n", "\r\n..\r\n") + "\r\n"; data += ".\r\n"; SendData(data); ReceiveData(); SendData("QUIT\r\n"); ReceiveData(); } finally { //切断する if (_stream != null) { _stream.Close(); } soc.Close(); } } //データを受信する private void ReceiveData() { Encoding enc = Encoding.GetEncoding(50220); byte[] data = new byte[1024]; int len; string str = ""; System.IO.MemoryStream ms = new System.IO.MemoryStream(); //すべて受信する do { //受信 len = _stream.Read(data, 0, data.Length); ms.Write(data, 0, len); //文字列に変換する str = enc.GetString(ms.ToArray()); } while (!str.EndsWith("\r\n") || System.Text.RegularExpressions.Regex.IsMatch( str, @"(?:^|\n)\d+-[^\r\n]*\r\n$")); ms.Close(); //表示 Console.Write("S: " + str); _recMsg = str; } //データを送信する private void SendData(string str) { Encoding enc = Encoding.GetEncoding(50220); //byte型配列に変換 byte[] data = enc.GetBytes(str); //送信 _stream.Write(data, 0, data.Length); //表示 Console.Write("C: " + str); } //JISでエンコードし、Base64に変換 private string GetBase64String(string str) { Encoding enc = Encoding.GetEncoding(50220); return Convert.ToBase64String(enc.GetBytes(str)); } //認証を行う private void Authenticate() { if (AuthMethod == SmtpAuthMethod.Plain) { //PLAIN SendData("AUTH PLAIN\r\n"); ReceiveData(); if (!_recMsg.StartsWith("334")) { if (_recMsg.StartsWith("502")) //認証の必要なし return; throw new ApplicationException(_recMsg); } string str = AuthUserName + '\0' + AuthUserName + '\0' + AuthPassword; SendData(GetBase64String(str) + "\r\n"); ReceiveData(); if (!_recMsg.StartsWith("235")) throw new ApplicationException(_recMsg); } else if (AuthMethod == SmtpAuthMethod.Login) { //LOGIN SendData("AUTH LOGIN\r\n"); ReceiveData(); if (!_recMsg.StartsWith("334")) { if (_recMsg.StartsWith("502")) //認証の必要なし return; throw new ApplicationException(_recMsg); } SendData(GetBase64String(AuthUserName) + "\r\n"); ReceiveData(); if (!_recMsg.StartsWith("334")) throw new ApplicationException(_recMsg); SendData(GetBase64String(AuthPassword) + "\r\n"); ReceiveData(); if (!_recMsg.StartsWith("235")) throw new ApplicationException(_recMsg); } } } }
(この記事は、「.NETプログラミング研究 第52号」で紹介したものを基にしています。) |
|
Copyright(C) DOBON!. All rights reserved.
|