• 追加された行はこの色です。
  • 削除された行はこの色です。
#title(.NETプログラミング研究 第52号)

#navi(.NETプログラミング研究)

#contents

*.NETプログラミング研究 第52号 [#lffd7c1e]

**.NET質問箱 [#tfbf2273]

「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。

-[[どぼん!のプログラミング掲示板>http://dobon.net/vb/bbs.html]]
-[[どぼん!のプログラミング掲示板>https://dobon.net/vb/bbs.html]]

***ポート番号を指定してSMTPでメールを送るには? [#od89c161]

#column(注意){{
この記事の最新版は「[[ポート番号を指定してSMTPでメールを送信する>http://dobon.net/vb/dotnet/internet/smtpport.html]]」で公開しています。
この記事の最新版は「[[ポート番号を指定してSMTPでメールを送信する>https://dobon.net/vb/dotnet/internet/smtpport.html]]」で公開しています。
}}

''【質問】''

System.Web.Mail.SmtpMailクラスでメールを送信する時、25以外のポート番号を指定することができないようです。25以外のポート番号を指定してメールを送信するには、どうしたらよいのでしょうか?

''【回答】''

.NET Framework 1.1では、MailMessageクラスにFieldsプロパティが加わり、これを使うことにより、CDOのフィールドにアクセスできるようになりました。これを使ってCDOのsmtpserverportフィールドを変更すれば、System.Web.Mail.SmtpMailクラスでもポート番号を指定してメールを送信することができます。

#code(csharp){{
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 = "これはテストです。";

//ポート番号を指定する
mail.Fields[
    "http://schemas.microsoft.com/cdo/configuration/smtpserverport"]
    = 25;

System.Web.Mail.SmtpMail.SmtpServer = "xxx.xxx.xxx";

//メールを送信
System.Web.Mail.SmtpMail.Send(mail);
}}

#code(vbnet){{
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 = "これはテストです。"

'ポート番号を指定する
mail.Fields.Item( _
    "http://schemas.microsoft.com/cdo/configuration/smtpserverport") _
    = 25

'SMTPサーバーを指定
System.Web.Mail.SmtpMail.SmtpServer = "xxx.xxx.xxx"
'メールを送信
System.Web.Mail.SmtpMail.Send(mail)
}}

参考:
-[[The Code Project - SMTP Authentication using System.Web.Mail (CDOSYS)>http://www.codeproject.com/dotnet/SystemWeb_Mail_SMTP_AUTH.asp]]
-[[CDO for Windows 2000 http://schemas.microsoft.com/cdo/configuration/ Namespace>http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_schema_configuration.asp]]

.NET Framework 1.0を使用している場合は、残念ながらこのようにMailMessageクラスのFieldsプロパティを使うことが出来ません。しかし、.NET Framework 1.0でもCDOを使用することは可能です。次にCDOを使ってメールを送信するサンプルを紹介しましょう。遅延バインディングを行っているため、ちょっと複雑になっています。

#code(csharp){{
Type t = Type.GetTypeFromProgID("CDO.Message");
object cdo = Activator.CreateInstance(t);
t.InvokeMember("From",
    System.Reflection.BindingFlags.SetProperty,
    null, cdo, new object[] {"xxx@xxx.xxx"});
t.InvokeMember("To",
    System.Reflection.BindingFlags.SetProperty,
    null, cdo, new object[] {"xxx@xxx.xxx"});
t.InvokeMember("Subject",
    System.Reflection.BindingFlags.SetProperty,
    null, cdo, new object[] {"テスト"});
t.InvokeMember("Textbody",
    System.Reflection.BindingFlags.SetProperty,
    null, cdo, new object[] {"これはテストです!!"});

object conf = t.InvokeMember("Configuration",
    System.Reflection.BindingFlags.GetProperty,
    null, cdo, null);
object fields = t.InvokeMember("Fields",
    System.Reflection.BindingFlags.GetProperty,
    null, conf, null);
t.InvokeMember("Item",
    System.Reflection.BindingFlags.SetProperty,
    null, fields,
    new object[] {
        "http://schemas.microsoft.com/cdo/configuration/sendusing",
        2});
//SMTPサーバーを指定する
t.InvokeMember("Item",
    System.Reflection.BindingFlags.SetProperty,
    null, fields,
    new object[] {
        "http://schemas.microsoft.com/cdo/configuration/smtpserver",
        "xxx.xxx.xxx"});
//ポート番号を指定する
t.InvokeMember("Item",
    System.Reflection.BindingFlags.SetProperty,
    null, fields,
    new object[] {
        "http://schemas.microsoft.com/cdo/configuration/smtpserverport",
         25});

t.InvokeMember("Update",
    System.Reflection.BindingFlags.InvokeMethod,
    null, fields,
    new object[] {});

//送信する
t.InvokeMember("Send",
    System.Reflection.BindingFlags.InvokeMethod,
    null, cdo,
    new object[] {});
}}

#code(vbnet){{
Dim t As Type = Type.GetTypeFromProgID("CDO.Message")
Dim cdo As Object = Activator.CreateInstance(t)

t.InvokeMember("From", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, cdo, New Object() {"xxx@xxx.xxx"})
t.InvokeMember("To", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, cdo, New Object() {"xxx@xxx.xxx"})
t.InvokeMember("Subject", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, cdo, New Object() {"テスト"})
t.InvokeMember("Textbody", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, cdo, New Object() {"これはテストです!!"})

Dim conf As Object = t.InvokeMember("Configuration", _
    System.Reflection.BindingFlags.GetProperty, _
    Nothing, cdo, Nothing)
Dim fields As Object = t.InvokeMember("Fields", _
    System.Reflection.BindingFlags.GetProperty, _
    Nothing, conf, Nothing)
t.InvokeMember("Item", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, fields, New Object() { _
    "http://schemas.microsoft.com/cdo/configuration/sendusing", _
    2})
'SMTPサーバーを指定する
t.InvokeMember("Item", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, fields, New Object() { _
    "http://schemas.microsoft.com/cdo/configuration/smtpserver", _
    "xxx.xxx.xxx"})
'ポート番号を指定する
t.InvokeMember("Item", _
    System.Reflection.BindingFlags.SetProperty, _
    Nothing, fields, New Object() { _
    "http://schemas.microsoft.com/cdo/configuration/smtpserverport", _
    25})

t.InvokeMember("Update", _
    System.Reflection.BindingFlags.InvokeMethod, _
    Nothing, fields, New Object() {})

'送信する
t.InvokeMember("Send", _
    System.Reflection.BindingFlags.InvokeMethod, _
    Nothing, cdo, New Object() {})
}}

CDOを使えない、あるいは使いたくないという場合は、自分でコードを書くか、誰かが作ったコンポーネントやクラスを使わせてもらうかということになるでしょう。例えば、Tatsuo Babaさんの「BASP21 DLL」を使わせていただくのも有効な方法の一つです。

-[[Baba Centerfolds>http://www.hi-ho.ne.jp/babaq/index.html]]

自分でコードを書くということになると、ソケットを使用することになります。この場合はもちろん、SMTPやMIMEに関する知識が必要です。SMTPについてRFCではRFC821で、さらにESMTPについてはRFC1869などで定義されています。

-[[SIMPLE MAIL TRANSFER PROTOCOL>http://www.ietf.org/rfc/rfc821.txt]]
-[[SMTP Service Extensions>http://www.ietf.org/rfc/rfc1869.txt]]

ソケットを使ってSMTPでメールを送信するサンプルは、次の「SMTP認証でメールを送信するには?」で示しますので、そちらをご覧ください。

○この記事の基になった掲示板のスレッド

-[[SMTPでメール送信にて | 投稿者(敬称略) きみ, りょう>http://dobon.net/vb/bbs/log3-5/2813.html]]
-[[SMTPでメール送信にて | 投稿者(敬称略) きみ, りょう>https://dobon.net/vb/bbs/log3-5/2813.html]]

***SMTP認証でメールを送信するには? / Socketを使ってSMTPでメールを送るには? [#h3e946df]

#column(注意){{
この記事の最新版は「[[SMTP認証でメールを送信する>http://dobon.net/vb/dotnet/internet/smtpauth.html]]」で公開しています。
この記事の最新版は「[[SMTP認証でメールを送信する>https://dobon.net/vb/dotnet/internet/smtpauth.html]]」で公開しています。
}}

''【質問】''

SMTP認証(SMTP-AUTH)によりメールを送信したいのですが、どのような方法がありますか?

''【回答】''

上で紹介した方法と同様に、.NET Framework 1.1では、MailMessageクラスのFieldsプロパティを使用することにより、System.Web.Mail.SmtpMailクラスでもSMTP認証によるメールの送信ができます。この方法は「The Code Project」で紹介されています。

-[[The Code Project - SMTP Authentication using System.Web.Mail (CDOSYS)>http://www.codeproject.com/dotnet/SystemWeb_Mail_SMTP_AUTH.asp]]

#code(csharp){{
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/smtsperver"]
    = "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);
}}

#code(vbnet){{
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/smtsperver") _
    = "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)
}}

CDOを使えない環境では、やはりこの方法は無理です。前の「ポート番号を指定してSMTPでメールを送るには?」で予告したように、ここではソケットを使ってSMTPメール送信するサンプルを示します。しかしこれはあくまでただの簡単なサンプルでしかありませんので、何も理解せずに、このコードをそのまま利用することは絶対にしないでください。RFCを読み気がない、あるいは理解できないという方は、「BASP21 DLL」や市販品をご利用ください。

なおこのクラスの使い方に関しては、エントリポイントのSmtpクラスのMainメソッドを参考にしてください。

#code(csharp){{
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
            {
                //切断する
                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);
            }
        }
    }
}
}}

#code(vbnet){{
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
                '切断する
                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
}}

○この記事の基になった掲示板のスレッド

-[[SMTP-AUTHでのメール送信 | 投稿者(敬称略) smith, Moo, 中博俊, 管理人>http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=8968&no=0]]
-[[SMTP-AUTHでのメール送信 | 投稿者(敬称略) smith, Moo, 中博俊, 管理人>https://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=8968&no=0]]

**コメント [#md24eea5]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2005-03-04 (金) 06:00:00,DOBON!,2010-03-22 (月) 02:00:53,DOBON!)

[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]