NonSoft

SMTP(TLS有り)でメール送信
(TcpClientソケット通信)サンプル(VB.NET)


 サンプル(ソース/コード)
ソケット通信(System.Net.Sockets.TcpClient)によるメール送信(TLS有り)のサンプルです。
メールで送受信されているコマンドとレスポンスの参考になると思います。

SMTP AUTH認証にはAUTH LOGINとAUTH CRAM-MD5とAUTH PLAIN等がありますが、
AUTH PLAINのみ実装しています。

※セキュリティで保護された接続(SMTP over SSL/TLSによる暗号化)について
VB.NET標準のメール送信(System.Net.Mail.SmtpClient)はTLSに対応していますが、
SMTP over SSLに対応していないようです。

このサンプルは、TLSをソケット通信で実装したサンプルです。

簡単にメール送受信したい方は、こちらのDLLをオススメします。
メール送信/受信DLL(VB.NET/C#.NET)

C#.NET版のサンプルソースはこちらです。
SMTP(TLS有り)でメール送信(TcpClientソケット通信)サンプル(C#.NET)

メール関係のその他のサンプルはこちらです。
メール送信/メール受信サンプル(VBS/VBA)
メール送信(SMTP認証/POP認証)のサンプル(VB.NET)
SMTP(SSL無し)でメール送信(TcpClientソケット通信)サンプル(VB.NET)
SMTP(SSL有り)でメール送信(TcpClientソケット通信)サンプル(VB.NET)
POP3(SSL無し)でメール受信(TcpClientソケット通信)サンプル(VB.NET)
POP3(SSL有り)でメール受信(TcpClientソケット通信)サンプル(VB.NET)
IMAP(SSL無し)でメール受信(TcpClientソケット通信)サンプル(VB.NET)
IMAP(SSL有り)でメール受信(TcpClientソケット通信)サンプル(VB.NET)

メール関係のツールはこちらです。
指令メール実行
受信メールを監視しメールタイトルのキーワードに対応したプログラムを実行するツールです。
ファイル監視人
ファイルやフォルダの更新時にメッセージ表示またはメール送信するツールです。
フォルダ監視人
フォルダ内のファイル更新時に更新通知(差分メール等)、指定プログラム実行するツールです。
PC状況メール通知(PcEvMail)
PC起動/PC終了/ログイン/ログアウト/ファイル更新時にメール通知/ログ出力するツールです。

ソケット通信関係のサンプルはこちらにもあります。
ソケット(TCP/IP)通信関係のサンプル

★フォーム(Form1.vb)
Public Class Form1
    Private cset As String = "ISO-2022-JP"
    Private serv As String = "smtp.xxx.com"
    Private port As Integer = 587
    Private user As String = "user"
    Private pass As String = "pass"
    Private fadr As String = "送信元<fr@xxx.com>"
    Private tadr As String = "送信先<to@xxx.com>"
    Private subj As String = "タイトル"
    Private body As String = "本文"

    ' (TLS有り)SMTP AUTH PLAINでメール送信(TcpClientソケット通信)サンプル
    ' グーグル(smtp.gmail.com)でメール送信
    Private Sub Button1_Click( _
        ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        ' TcpClientソケット通信定義
        Dim stream As Object
        Dim client As System.Net.Sockets.TcpClient

        ' SMTPサーバーに接続
        client = New System.Net.Sockets.TcpClient
        client.Connect(serv, port)

        ' SSL無しの実装---------------------------------------------------------------
        ' 通信開始(SSL無し)
        stream = client.GetStream()
        ' ----------------------------------------------------------------------------

        ' SMTPサーバー接続時のレスポンス受信
        Dim rstr As String
        rstr = StreamWriteAndRead(stream, "", cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' EHLOの送信
        Dim pcname As String = System.Net.Dns.GetHostName()
        rstr = StreamWriteAndRead(stream, "EHLO " & pcname & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' TLSの実装-------------------------------------------------------------------
        ' STARTTLSの送信
        rstr = StreamWriteAndRead(stream, "STARTTLS" & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' SSLの開始
        stream = New System.Net.Security.SslStream(client.GetStream())
        stream.AuthenticateAsClient(serv)

        ' EHLOの送信
        rstr = StreamWriteAndRead(stream, "EHLO " & pcname & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If
        ' ----------------------------------------------------------------------------

        ' SMTP AUTH 認証の実装--------------------------------------------------------
        ' AUTH PLAINの送信(LOGINやCRAM-MD5はNonMailNet.dllをお試しください)
        rstr = StreamWriteAndRead(stream, "AUTH PLAIN" & vbCrLf, cset)
        If rstr.StartsWith("502") = False Then
            If rstr.StartsWith("3") = False Then
                Throw New Exception("エラー:" & rstr)
            End If
            ' ユーザIDとパスワードの生成
            Dim upas As String = user & ControlChars.NullChar & _
                                 user & ControlChars.NullChar & pass
            ' ユーザIDとパスワードの送信
            rstr = StreamWriteAndRead(stream, Enc_Base64_1(upas, cset) & vbCrLf, cset)
            If rstr.StartsWith("2") = False Then
                Throw New Exception("エラー:" & rstr)
            End If
        End If
        ' ----------------------------------------------------------------------------

        ' MAIL FROMの送信
        fadr = fadr.Trim()
        Dim fa As String = New System.Net.Mail.MailAddress(fadr).Address
        rstr = StreamWriteAndRead(stream, "MAIL FROM:<" & fa & ">" & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' RCPT TOの送信
        tadr = tadr.Trim()
        Dim ta As String = New System.Net.Mail.MailAddress(tadr).Address
        rstr = StreamWriteAndRead(stream, "RCPT TO:<" & ta & ">" & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' DATAの送信
        rstr = StreamWriteAndRead(stream, "DATA" & vbCrLf, cset)
        If rstr.StartsWith("2") = False And rstr.StartsWith("3") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' 本文DATAの作成(From)
        Dim data As String = ""
        Dim frd As String = New System.Net.Mail.MailAddress(fadr).DisplayName
        data &= "From: " & Enc_Base64_2(frd, cset) & "<" & fa & ">" & vbCrLf

        ' 本文DATAの作成(To)
        Dim tod As String = New System.Net.Mail.MailAddress(tadr).DisplayName
        data &= "To: " & Enc_Base64_2(tod, cset) & "<" & ta & ">" & vbCrLf

        ' 本文DATAの作成(Subject)
        data &= "Subject: " & Enc_Base64_2(subj, cset) & vbCrLf

        ' 本文DATAの作成(MIME-Version)
        data &= "MIME-Version: 1.0" & vbCrLf

        ' 本文DATAの作成(Content-Type) -- 添付ファイル無しの時 --
        data &= "Content-Type: text/plain; charset=""" & cset & """" & vbCrLf
        ' (参考)添付ファイル有りの時は(Content-Type: multipart/mixed; boundary="XXX")

        ' 本文DATAの作成(Content-Transfer-Encoding)
        data &= "Content-Transfer-Encoding: 7bit" & vbCrLf & vbCrLf

        ' 本文DATAの作成(本文)
        data &= body & vbCrLf

        ' 本文DATAの作成(.を..に変換)
        data = data.Replace(vbCrLf & "." & vbCrLf, vbCrLf & ".." & vbCrLf)

        ' 本文DATAの作成(.を付加)
        data &= vbCrLf & "." & vbCrLf

        ' 本文DATAの送信
        rstr = StreamWriteAndRead(stream, data, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If

        ' QUITの送信
        rstr = StreamWriteAndRead(stream, "QUIT" & vbCrLf, cset)
        If rstr.StartsWith("2") = False Then
            Throw New Exception("エラー:" & rstr)
        End If
    End Sub

    ''' <summary>
    ''' メールサーバとの送受信
    ''' </summary>
    ''' <param name="stm">メールサーバ通信ストリーム</param>
    ''' <param name="req">リクエスト(コマンド)</param>
    ''' <param name="cst">文字コード</param>
    ''' <returns>レスポンス</returns>
    ''' <remarks></remarks>
    Private Function StreamWriteAndRead( _
        ByVal stm As Object, _
        ByVal req As String, _
        ByVal cst As String) As String

        ' メールサーバへリクエスト送信
        If req <> "" Then
            Dim sdat() As Byte
            sdat = System.Text.Encoding.GetEncoding(cst).GetBytes(req)
            stm.Write(sdat, 0, sdat.Length)
            stm.Flush()
        End If

        ' メールサーバからのレスポンス受信
        Dim rstr As String = ""
        Dim rdat() As Byte
        ReDim rdat(1024 * 1024 - 1)
        Dim l As Integer = stm.Read(rdat, 0, rdat.Length)
        If l > 0 Then
            ReDim Preserve rdat(l - 1)
            rstr = System.Text.Encoding.GetEncoding(cst).GetString(rdat)
        Else
            Throw New Exception("Read Error.")
        End If

        ' レスポンス応答
        Return rstr
    End Function

    ''' <summary>
    ''' 指定文字コードのBASE64エンコード
    ''' </summary>
    ''' <param name="str">オリジナル文字列</param>
    ''' <returns>エンコード結果文字列</returns>
    ''' <param name="cst">文字コード</param>
    ''' <remarks></remarks>
    Private Function Enc_Base64_1(ByVal str As String, ByVal cst As String) As String
        If str = "" Then Return ""
        Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(cst)
        Return Convert.ToBase64String(enc.GetBytes(str))
    End Function

    ''' <summary>
    ''' 指定文字コードのBASE64エンコード
    ''' </summary>
    ''' <param name="str">オリジナル文字列</param>
    ''' <param name="cst">文字コード</param>
    ''' <returns>エンコード結果文字列</returns>
    ''' <remarks>"=?ISO-2022-JP?B?"〜"?="フォーマット</remarks>
    Private Function Enc_Base64_2(ByVal str As String, ByVal cst As String) As String
        If str = "" Then Return ""
        Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding(cst)
        Return "=?" & cst & "?B?" & Convert.ToBase64String(enc.GetBytes(str)) & "?="
    End Function
End Class