#navi(contents-page-name): No such page: .NET プログラミング研究

.NETプログラミング研究 第52号

.NET質問箱

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

ポート番号を指定してSMTPでメールを送るには?

注意

この記事の最新版は「ポート番号を指定してSMTPでメールを送信する」で公開しています。

【質問】

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

【回答】

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
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);
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
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)

参考:

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
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[] {});
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
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」を使わせていただくのも有効な方法の一つです。

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

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

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

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

注意

この記事の最新版は「SMTP認証でメールを送信する」で公開しています。

【質問】

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

【回答】

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
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);
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
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メソッドを参考にしてください。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
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);
            }
        }
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
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

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

コメント



ページ情報
  • カテゴリ : .NET
  • 作成日 : 2005-03-04 (金) 06:00:00
  • 作成者 : DOBON!
  • 最終編集日 : 2010-03-22 (月) 02:00:53
  • 最終編集者 : DOBON!
[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]