注意:ここで紹介しているコードを実際に使用する場合は、SMTPサーバー、送信者、送信先などを必ず変更してください。
SMTPでメールを送信する場合、「SMTPでメールを送信する」で紹介したように、SmtpClientクラスやSmtpMailクラスを使えば簡単です。しかしここでは、あえてSocketを使用して直接SMTPサーバーとやり取りをしてメールを送信することに挑戦します。
この場合はもちろん、SMTPやMIMEに関する知識が必要です。SMTPについてRFCではRFC821(SIMPLE MAIL TRANSFER PROTOCOL)で、さらにESMTPについてはRFC1869(SMTP Service Extensions)などで定義されています。
ここでは、ソケットを使ってSMTPメール送信するサンプルのみを示します。このサンプルは、コンソールアプリケーションとして実行できるようになっています。使い方は、ProgramクラスのMainメソッドをご覧ください。
このサンプルは、SMTPとプログラミングの知識がすでにある程度ある方(あるいは、ご自分で勉強できる方)の参考になればと思い作成したものです。よって、実用には耐えませんし、申し訳ありませんが、コード内のコメント以外に詳しい説明もしません。
AUTH PLAIN、AUTH LOGIN、CRAM-MD5での認証に対応しています。.NET Framework 2.0以上で動作すると思いますが、CRAM-MD5での認証が必要なければ、その部分(HMACMD5クラスを使っている箇所)を削除すれば、すべてのバージョンの.NET Frameworkで動作すると思います。
Imports System.Net.Sockets Imports System.Text Namespace Dobon.Mail Public Class Program ''' <summary> ''' テスト用のエントリポイント ''' </summary> Public Shared Sub Main() 'Debug.Writeでコンソールに出力するようにする System.Diagnostics.Debug.Listeners.Clear() System.Diagnostics.Debug.Listeners.Add( _ New System.Diagnostics.ConsoleTraceListener()) 'SmtpMailMessageオブジェクトを作成する Dim mail As New SmtpMailMessage() 'From mail.From = "xxx@xxx.xxx" 'To mail.[To] = "xxx@xxx.xxx" 'Subject mail.Subject = "テスト" '本文 mail.Body = "これはテストです。" 'Smtpオブジェクトを作成する Dim smtp As New Smtp() 'SMTPサーバー名 smtp.SmtpServer = "localhost" 'ポート番号 smtp.SmtpPort = 25 '認証が必要な時は、認証方法を設定する smtp.AuthMethod = SmtpAuthMethod.CramMd5 smtp.AuthUserName = "user" smtp.AuthPassword = "pass" 'メールを送信する smtp.Send(mail) Console.ReadLine() End Sub End Class ''' <summary> ''' 送信用のメールメッセージを表すクラス ''' </summary> Public Class SmtpMailMessage Private _from As String = "" ''' <summary> ''' 送信者のメールアドレス ''' </summary> Public Property From() As String Get Return _from End Get Set(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(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(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(value As String) _body = value End Set End Property Private _encoding As Encoding = Encoding.GetEncoding(50220) ''' <summary> ''' 使用するエンコーディング ''' </summary> Public Property Encoding() As Encoding Get Return _encoding End Get Set(value As Encoding) _encoding = value End Set End Property End Class ''' <summary> ''' Smtpクラスで発生するエラーを表したクラス ''' </summary> Public Class SmtpException Inherits Exception Public Sub New() MyBase.New() End Sub Public Sub New(message As String) MyBase.New(message) End Sub Public Sub New(message As String, inner As Exception) MyBase.New(message, inner) End Sub End Class ''' <summary> ''' SMTPの認証方法を表す列挙体 ''' </summary> Public Enum SmtpAuthMethod ''' <summary> ''' 認証を行わない ''' </summary> None ''' <summary> ''' AUTH PLAIN ''' </summary> Plain ''' <summary> ''' AUTH LOGIN ''' </summary> Login ''' <summary> ''' AUTH CRAM-MD5 ''' </summary> CramMd5 End Enum ''' <summary> ''' SMTPでメールを送信するためのクラス ''' </summary> Public Class Smtp Implements IDisposable #Region "プロパティ" Private _smtpServer As String = "" ''' <summary> ''' SMTPサーバー ''' </summary> Public Property SmtpServer() As String Get Return _smtpServer End Get Set(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(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(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(value As String) _authPassword = value End Set End Property Private _authMethod As SmtpAuthMethod = SmtpAuthMethod.None ''' <summary> ''' 使用する認証方法 ''' </summary> Public Property AuthMethod() As SmtpAuthMethod Get Return _authMethod End Get Set(value As SmtpAuthMethod) _authMethod = value End Set End Property Private _heloName As String = System.Net.Dns.GetHostName() ''' <summary> ''' EHLOで送信するドメイン名 ''' </summary> Public Property HeloName() As String Get Return _heloName End Get Set(value As String) _heloName = value End Set End Property #End Region #Region "フィールド" Private _socket As TcpClient Private _stream As NetworkStream Private _reader As System.IO.StreamReader Private _writer As System.IO.StreamWriter 'SMTPサーバーから受信したメッセージ Private _receivedMessage As String 'SMTPサーバーから受信したReply Code Private _receivedCode As Integer Private _encoding As Encoding #End Region #Region "パブリックメソッド" ''' <summary> ''' メールを送信する ''' </summary> ''' <param name="mail">送信するメール</param> Public Sub Send(mail As SmtpMailMessage) '初期設定 _encoding = mail.Encoding Try 'SMTPサーバーと接続する Connect() 'EHLO SendHeloCommand(HeloName) 'AUTH If AuthMethod <> SmtpAuthMethod.None Then Authenticate() End If 'MAIL FROM SendMailFromCommand(mail.From) 'RCPT TO SendRcptToCommand(mail.[To]) 'DATA SendDataCommand(mail) 'QUIT SendQuitCommand() Finally '切断する Close() End Try End Sub ''' <summary> ''' SMTPサーバーと接続する ''' </summary> Public Sub Connect() If _socket IsNot Nothing Then Close() End If 'TcpClientオブジェクトを作成する _socket = New TcpClient() 'SMTPサーバーと接続する _socket.Connect(SmtpServer, SmtpPort) 'サーバーとデータの送受信を行うストリームを取得する _stream = _socket.GetStream() _reader = New System.IO.StreamReader(_stream, _encoding) _writer = New System.IO.StreamWriter(_stream, _encoding) 'サーバーからのはじめのメッセージを受信 ReceiveData() If _receivedCode <> 220 Then Throw New SmtpException(_receivedMessage) End If End Sub ''' <summary> ''' SMTPサーバーに文字列を送信し、応答を受信する ''' </summary> ''' <param name="message">送信する文字列</param> ''' <returns>受信した応答</returns> Public Function SendAndReceiveData(message As String) As String If _socket Is Nothing Then Throw New SmtpException("サーバーに接続していません。") End If SendData(message) ReceiveData() Return _receivedMessage End Function ''' <summary> ''' SMTPサーバーとの接続を終了する ''' </summary> Public Sub Close() Dispose() End Sub Public Sub Dispose() Implements IDisposable.Dispose If Not (_reader Is Nothing) Then _reader.Close() End If If Not (_writer Is Nothing) Then _writer.Close() End If If Not (_stream Is Nothing) Then _stream.Close() End If If Not (_socket Is Nothing) Then _socket.Close() End If _socket = Nothing End Sub #End Region #Region "プライベートメソッド" 'サーバーからデータを受信する Private Sub ReceiveData() Dim buffer As New StringBuilder() Dim line As String Do '1行読み取る line = _reader.ReadLine() If line Is Nothing Then Exit Do End If buffer.Append(line).Append(vbCrLf) '表示 System.Diagnostics.Debug.WriteLine("S: " & line) Loop While System.Text.RegularExpressions.Regex.IsMatch( _ line, "^\d+-") '受信したメッセージとコードをフィールドに入れる _receivedMessage = buffer.ToString() _receivedCode = Integer.Parse(_receivedMessage.Substring(0, 3)) End Sub 'サーバーにデータを送信する Private Sub SendData(str As String) '送信 _writer.Write(str) _writer.Flush() '表示 System.Diagnostics.Debug.Write("C: " & str) End Sub 'エンコードし、Base64に変換 Private Function GetBase64String(str As String) As String Return Convert.ToBase64String(_encoding.GetBytes(str)) End Function 'EHLOコマンドを送る Private Sub SendHeloCommand(domainName As String) SendAndReceiveData("EHLO " & domainName & vbCrLf) If _receivedCode <> 250 Then Throw New SmtpException(_receivedMessage) End If End Sub 'MAIL FROMコマンドを送る Private Sub SendMailFromCommand(fromAddress As String) SendAndReceiveData("MAIL FROM:<" & fromAddress & ">" & vbCrLf) If _receivedCode <> 250 Then Throw New SmtpException(_receivedMessage) End If End Sub 'RCPT TOコマンドを送る Private Sub SendRcptToCommand(toAddress As String) SendAndReceiveData("RCPT TO:<" & toAddress & ">" & vbCrLf) If _receivedCode < 250 OrElse 251 < _receivedCode Then Throw New SmtpException(_receivedMessage) End If End Sub 'DATAコマンドを送る Private Sub SendDataCommand(mail As SmtpMailMessage) SendAndReceiveData("DATA" & vbCrLf) If _receivedCode <> 354 Then Throw New SmtpException(_receivedMessage) End If '送信データを作成する Dim data As String = CreateSendStringDataFromMessage(mail) SendAndReceiveData(data) If _receivedCode <> 250 Then Throw New SmtpException(_receivedMessage) End If End Sub 'SmtpMailMessageをDATAコマンドで送信する文字列に変換する Private Function CreateSendStringDataFromMessage( _ mail As SmtpMailMessage) As String Dim data As New StringBuilder() data.Append("From: ").Append(mail.From).Append(vbCrLf) data.Append("To: ").Append(mail.[To]).Append(vbCrLf) '件名をBase64でエンコード data.Append("Subject: =?" & _encoding.BodyName & "?B?"). _ Append(GetBase64String(mail.Subject)).Append("?="). _ Append(vbCrLf) data.Append("MIME-Version: 1.0" & vbCrLf) data.Append("Content-Transfer-Encoding: 7bit" & vbCrLf) data.Append("Content-Type: text/plain; charset=" & _ _encoding.BodyName & vbCrLf) data.Append(vbCrLf).Append(mail.Body.Replace( _ vbCrLf & "." & vbCrLf, vbCrLf & ".." & vbCrLf)) data.Append(vbCrLf & "." & vbCrLf) Return data.ToString() End Function 'QUITコマンドを送る Private Sub SendQuitCommand() SendAndReceiveData("QUIT" & vbCrLf) If _receivedCode <> 221 Then Throw New SmtpException(_receivedMessage) End If End Sub '認証を行う Private Sub Authenticate() Select Case AuthMethod Case SmtpAuthMethod.Plain AuthenticateWithAuthPlain() Exit Select Case SmtpAuthMethod.Login AuthenticateWithAuthLogin() Exit Select Case SmtpAuthMethod.CramMd5 AuthenticateWithCramMd5() Exit Select End Select End Sub 'AUTH PLAINで認証を行う Private Sub AuthenticateWithAuthPlain() SendAndReceiveData("AUTH PLAIN" & vbCrLf) If _receivedCode <> 334 Then If _receivedCode = 502 Then '認証の必要なし Return End If Throw New SmtpException(_receivedMessage) End If Dim str As String = AuthUserName & ControlChars.NullChar & _ AuthUserName & ControlChars.NullChar & AuthPassword SendAndReceiveData(GetBase64String(str) & vbCrLf) If _receivedCode <> 235 Then Throw New SmtpException(_receivedMessage) End If End Sub 'AUTH LOGINで認証を行う Private Sub AuthenticateWithAuthLogin() SendAndReceiveData("AUTH LOGIN" & vbCrLf) If _receivedCode <> 334 Then If _receivedCode = 502 Then '認証の必要なし Return End If Throw New SmtpException(_receivedMessage) End If SendAndReceiveData(GetBase64String(AuthUserName) & vbCrLf) If _receivedCode <> 334 Then Throw New SmtpException(_receivedMessage) End If SendAndReceiveData(GetBase64String(AuthPassword) & vbCrLf) If _receivedCode <> 235 Then Throw New SmtpException(_receivedMessage) End If End Sub 'CRAM-MD5で認証を行う Private Sub AuthenticateWithCramMd5() SendAndReceiveData("AUTH CRAM-MD5" & vbCrLf) If _receivedCode <> 334 Then If _receivedCode = 502 Then '認証の必要なし Return End If Throw New SmtpException(_receivedMessage) End If SendAndReceiveData(CreateCramMd5ResponseString( _ _receivedMessage.Substring(4), AuthUserName, AuthPassword) _ & vbCrLf) If _receivedCode <> 235 Then Throw New SmtpException(_receivedMessage) End If End Sub 'CRAM-MD5で返す文字列を計算する Private Shared Function CreateCramMd5ResponseString( _ challenge As String, username As String, password As String) _ As String 'デコードする Dim decCha As Byte() = Convert.FromBase64String(challenge) 'passwordをキーとしてHMAC-MD5で暗号化する Dim hmacMd5 As New System.Security.Cryptography.HMACMD5( _ Encoding.UTF8.GetBytes(password)) Dim encCha As Byte() = hmacMd5.ComputeHash(decCha) hmacMd5.Clear() '16進数の文字列にする Dim hexCha As String = BitConverter.ToString(encCha). _ Replace("-", "").ToLower() 'usernameを付ける hexCha = username & " " & hexCha 'Base64で文字列にする Return Convert.ToBase64String(Encoding.UTF8.GetBytes(hexCha)) End Function #End Region End Class End Namespace
using System; using System.Net.Sockets; using System.Text; namespace Dobon.Mail { public class Program { /// <summary> /// テスト用のエントリポイント /// </summary> public static void Main() { //Debug.Writeでコンソールに出力するようにする System.Diagnostics.Debug.Listeners.Clear(); System.Diagnostics.Debug.Listeners.Add( new System.Diagnostics.ConsoleTraceListener()); //SmtpMailMessageオブジェクトを作成する SmtpMailMessage mail = new SmtpMailMessage(); //From mail.From = "xxx@xxx.xxx"; //To mail.To = "xxx@xxx.xxx"; //Subject mail.Subject = "テスト"; //本文 mail.Body = "これはテストです。"; //Smtpオブジェクトを作成する Smtp smtp = new Smtp(); //SMTPサーバー名 smtp.SmtpServer = "localhost"; //ポート番号 smtp.SmtpPort = 25; //認証が必要な時は、認証方法を設定する smtp.AuthMethod = SmtpAuthMethod.CramMd5; smtp.AuthUserName = "user"; smtp.AuthPassword = "pass"; //メールを送信する smtp.Send(mail); Console.ReadLine(); } } /// <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; } } private Encoding _encoding = Encoding.GetEncoding(50220); /// <summary> /// 使用するエンコーディング /// </summary> public Encoding Encoding { get { return _encoding; } set { _encoding = value; } } } /// <summary> /// Smtpクラスで発生するエラーを表したクラス /// </summary> public class SmtpException : Exception { public SmtpException() : base() { } public SmtpException(string message) : base(message) { } public SmtpException(string message, Exception inner) : base(message, inner) { } } /// <summary> /// SMTPの認証方法を表す列挙体 /// </summary> public enum SmtpAuthMethod { /// <summary> /// 認証を行わない /// </summary> None, /// <summary> /// AUTH PLAIN /// </summary> Plain, /// <summary> /// AUTH LOGIN /// </summary> Login, /// <summary> /// AUTH CRAM-MD5 /// </summary> CramMd5 } /// <summary> /// SMTPでメールを送信するためのクラス /// </summary> public class Smtp : IDisposable { #region プロパティ 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; } } private SmtpAuthMethod _authMethod = SmtpAuthMethod.None; /// <summary> /// 使用する認証方法 /// </summary> public SmtpAuthMethod AuthMethod { get { return _authMethod; } set { _authMethod = value; } } private string _heloName = System.Net.Dns.GetHostName(); /// <summary> /// EHLOで送信するドメイン名 /// </summary> public string HeloName { get { return _heloName; } set { _heloName = value; } } #endregion #region フィールド private TcpClient _socket; private NetworkStream _stream; private System.IO.StreamReader _reader; private System.IO.StreamWriter _writer; //SMTPサーバーから受信したメッセージ private string _receivedMessage; //SMTPサーバーから受信したReply Code private int _receivedCode; private Encoding _encoding; #endregion #region パブリックメソッド /// <summary> /// メールを送信する /// </summary> /// <param name="mail">送信するメール</param> public void Send(SmtpMailMessage mail) { //初期設定 _encoding = mail.Encoding; try { //SMTPサーバーと接続する Connect(); //EHLO SendHeloCommand(HeloName); //AUTH if (AuthMethod != SmtpAuthMethod.None) Authenticate(); //MAIL FROM SendMailFromCommand(mail.From); //RCPT TO SendRcptToCommand(mail.To); //DATA SendDataCommand(mail); //QUIT SendQuitCommand(); } finally { //切断する Close(); } } /// <summary> /// SMTPサーバーと接続する /// </summary> public void Connect() { if (_socket != null) Close(); //TcpClientオブジェクトを作成する _socket = new TcpClient(); //SMTPサーバーと接続する _socket.Connect(SmtpServer, SmtpPort); //サーバーとデータの送受信を行うストリームを取得する _stream = _socket.GetStream(); _reader = new System.IO.StreamReader(_stream, _encoding); _writer = new System.IO.StreamWriter(_stream, _encoding); //サーバーからのはじめのメッセージを受信 ReceiveData(); if (_receivedCode != 220) throw new SmtpException(_receivedMessage); } /// <summary> /// SMTPサーバーに文字列を送信し、応答を受信する /// </summary> /// <param name="message">送信する文字列</param> /// <returns>受信した応答</returns> public string SendAndReceiveData(string message) { if (_socket == null) throw new SmtpException("サーバーに接続していません。"); SendData(message); ReceiveData(); return _receivedMessage; } /// <summary> /// SMTPサーバーとの接続を終了する /// </summary> public void Close() { Dispose(); } public void Dispose() { if (_reader != null) { _reader.Close(); } if (_writer != null) { _writer.Close(); } if (_stream != null) { _stream.Close(); } if (_socket != null) { _socket.Close(); } _socket = null; } #endregion #region プライベートメソッド //サーバーからデータを受信する private void ReceiveData() { StringBuilder buffer = new StringBuilder(); string line; do { //1行読み取る line = _reader.ReadLine(); if (line == null) { break; } buffer.Append(line).Append("\r\n"); //表示 System.Diagnostics.Debug.WriteLine("S: " + line); } while (System.Text.RegularExpressions.Regex.IsMatch( line, @"^\d+-")); //受信したメッセージとコードをフィールドに入れる _receivedMessage = buffer.ToString(); _receivedCode = int.Parse(_receivedMessage.Substring(0, 3)); } //サーバーにデータを送信する private void SendData(string str) { //送信 _writer.Write(str); _writer.Flush(); //表示 System.Diagnostics.Debug.Write("C: " + str); } //エンコードし、Base64に変換 private string GetBase64String(string str) { return Convert.ToBase64String(_encoding.GetBytes(str)); } //EHLOコマンドを送る private void SendHeloCommand(string domainName) { SendAndReceiveData("EHLO " + domainName + "\r\n"); if (_receivedCode != 250) throw new SmtpException(_receivedMessage); } //MAIL FROMコマンドを送る private void SendMailFromCommand(string fromAddress) { SendAndReceiveData("MAIL FROM:<" + fromAddress + ">\r\n"); if (_receivedCode != 250) throw new SmtpException(_receivedMessage); } //RCPT TOコマンドを送る private void SendRcptToCommand(string toAddress) { SendAndReceiveData("RCPT TO:<" + toAddress + ">\r\n"); if (_receivedCode < 250 || 251 < _receivedCode) throw new SmtpException(_receivedMessage); } //DATAコマンドを送る private void SendDataCommand(SmtpMailMessage mail) { SendAndReceiveData("DATA\r\n"); if (_receivedCode != 354) throw new SmtpException(_receivedMessage); //送信データを作成する string data = CreateSendStringDataFromMessage(mail); SendAndReceiveData(data); if (_receivedCode != 250) throw new SmtpException(_receivedMessage); } //SmtpMailMessageをDATAコマンドで送信する文字列に変換する private string CreateSendStringDataFromMessage(SmtpMailMessage mail) { StringBuilder data = new StringBuilder(); data.Append("From: ").Append(mail.From).Append("\r\n"); data.Append("To: ").Append(mail.To).Append("\r\n"); //件名をBase64でエンコード data.Append("Subject: =?" + _encoding.BodyName + "?B?"). Append(GetBase64String(mail.Subject)). Append("?=").Append("\r\n"); data.Append("MIME-Version: 1.0\r\n"); data.Append("Content-Transfer-Encoding: 7bit\r\n"); data.Append("Content-Type: text/plain; charset=" + _encoding.BodyName + "\r\n"); data.Append("\r\n"). Append(mail.Body.Replace("\r\n.\r\n", "\r\n..\r\n")); data.Append("\r\n.\r\n"); return data.ToString(); } //QUITコマンドを送る private void SendQuitCommand() { SendAndReceiveData("QUIT\r\n"); //if (_receivedCode != 221) // throw new SmtpException(_receivedMessage); } //認証を行う private void Authenticate() { switch (AuthMethod) { case SmtpAuthMethod.Plain: AuthenticateWithAuthPlain(); break; case SmtpAuthMethod.Login: AuthenticateWithAuthLogin(); break; case SmtpAuthMethod.CramMd5: AuthenticateWithCramMd5(); break; } } //AUTH PLAINで認証を行う private void AuthenticateWithAuthPlain() { SendAndReceiveData("AUTH PLAIN\r\n"); if (_receivedCode != 334) { if (_receivedCode == 502) //認証の必要なし return; throw new SmtpException(_receivedMessage); } string str = AuthUserName + '\0' + AuthUserName + '\0' + AuthPassword; SendAndReceiveData(GetBase64String(str) + "\r\n"); if (_receivedCode != 235) throw new SmtpException(_receivedMessage); } //AUTH LOGINで認証を行う private void AuthenticateWithAuthLogin() { SendAndReceiveData("AUTH LOGIN\r\n"); if (_receivedCode != 334) { if (_receivedCode == 502) //認証の必要なし return; throw new SmtpException(_receivedMessage); } SendAndReceiveData(GetBase64String(AuthUserName) + "\r\n"); if (_receivedCode != 334) throw new SmtpException(_receivedMessage); SendAndReceiveData(GetBase64String(AuthPassword) + "\r\n"); if (_receivedCode != 235) throw new SmtpException(_receivedMessage); } //CRAM-MD5で認証を行う private void AuthenticateWithCramMd5() { SendAndReceiveData("AUTH CRAM-MD5\r\n"); if (_receivedCode != 334) { if (_receivedCode == 502) //認証の必要なし return; throw new SmtpException(_receivedMessage); } SendAndReceiveData(CreateCramMd5ResponseString( _receivedMessage.Substring(4), AuthUserName, AuthPassword) + "\r\n"); if (_receivedCode != 235) throw new SmtpException(_receivedMessage); } //CRAM-MD5で返す文字列を計算する private static string CreateCramMd5ResponseString( string challenge, string username, string password) { //デコードする byte[] decCha = Convert.FromBase64String(challenge); //passwordをキーとしてHMAC-MD5で暗号化する System.Security.Cryptography.HMACMD5 hmacMd5 = new System.Security.Cryptography.HMACMD5( Encoding.UTF8.GetBytes(password)); byte[] encCha = hmacMd5.ComputeHash(decCha); hmacMd5.Clear(); //16進数の文字列にする string hexCha = BitConverter.ToString(encCha). Replace("-", "").ToLower(); //usernameを付ける hexCha = username + " " + hexCha; //Base64で文字列にする return Convert.ToBase64String(Encoding.UTF8.GetBytes(hexCha)); } #endregion } }
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。