NonSoft

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


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

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

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

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

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

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

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

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

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

★フォーム(Form1.cs)
public partial class Form1 : Form
{
    private String cset = "ISO-2022-JP";
    private String serv = "smtp.xxx.com";
    private int port = 465;
    private String user = "user";
    private String pass = "pass";
    private String fadr = "送信元<fr@xxx.com>";
    private String tadr = "送信先<to@xxx.com>";
    private String subj = "タイトル";
    private String body = "本文";

    // (SSL有り)SMTP AUTH PLAINでメール送信(TcpClientソケット通信)サンプル
    // グーグル(smtp.gmail.com)でメール送信
    private void button1_Click(object sender, EventArgs e)
    {
        // TcpClientソケット通信定義
        System.Net.Security.SslStream stream;
        System.Net.Sockets.TcpClient client;

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

        // SSLの実装------------------------------------------------------------------
        // 通信開始(SSL有り)
        stream = new System.Net.Security.SslStream(client.GetStream());
        stream.AuthenticateAsClient(serv);
        // ---------------------------------------------------------------------------

        // SMTPサーバー接続時のレスポンス受信
        String rstr;
        rstr = StreamWriteAndRead(stream, "", cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // EHLOの送信
        String pcname = System.Net.Dns.GetHostName();
        rstr = StreamWriteAndRead(stream, "EHLO " + pcname + "\r\n", cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // SMTP AUTH 認証の実装-------------------------------------------------------
        // AUTH PLAINの送信(LOGINやCRAM-MD5はNonMailNet.dllをお試しください)
        rstr = StreamWriteAndRead(stream, "AUTH PLAIN" + "\r\n", cset);
        if (rstr.StartsWith("502") == false)
        {
            if (rstr.StartsWith("3") == false)
            {
                throw new Exception("エラー:" + rstr);
            }
            // ユーザIDとパスワードの生成
            String upas = user + "\0" +
                          user + "\0" + pass;
            // ユーザIDとパスワードの送信
            rstr = StreamWriteAndRead(stream, Enc_Base64_1(upas, cset) + "\r\n", cset);
            if (rstr.StartsWith("2") == false)
            {
                throw new Exception("エラー:" + rstr);
            }
        }
        // ---------------------------------------------------------------------------

        // MAIL FROMの送信
        fadr = fadr.Trim();
        String fa = new System.Net.Mail.MailAddress(fadr).Address;
        rstr = StreamWriteAndRead(stream, "MAIL FROM:<" + fa + ">" + "\r\n", cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // RCPT TOの送信
        tadr = tadr.Trim();
        String ta = new System.Net.Mail.MailAddress(tadr).Address;
        rstr = StreamWriteAndRead(stream, "RCPT TO:<" + ta + ">" + "\r\n", cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // DATAの送信
        rstr = StreamWriteAndRead(stream, "DATA" + "\r\n", cset);
        if (rstr.StartsWith("2") == false && rstr.StartsWith("3") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // 本文DATAの作成(From)
        String data = "";
        String frd = new System.Net.Mail.MailAddress(fadr).DisplayName;
        data += "From: " + Enc_Base64_2(frd, cset) + "<" + fa + ">" + "\r\n";

        // 本文DATAの作成(To)
        String tod = new System.Net.Mail.MailAddress(tadr).DisplayName;
        data += "To: " + Enc_Base64_2(tod, cset) + "<" + ta + ">" + "\r\n";

        // 本文DATAの作成(Subject)
        data += "Subject: " + Enc_Base64_2(subj, cset) + "\r\n";

        // 本文DATAの作成(MIME-Version)
        data += "MIME-Version: 1.0" + "\r\n";

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

        // 本文DATAの作成(Content-Transfer-Encoding)
        data += "Content-Transfer-Encoding: 7bit" + "\r\n" + "\r\n";

        // 本文DATAの作成(本文)
        data += body + "\r\n";

        // 本文DATAの作成(.を..に変換)
        data = data.Replace("\r\n" + "." + "\r\n", "\r\n" + ".." + "\r\n");

        // 本文DATAの作成(.を付加)
        data += "\r\n" + "." + "\r\n";

        // 本文DATAの送信
        rstr = StreamWriteAndRead(stream, data, cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }

        // QUITの送信
        rstr = StreamWriteAndRead(stream, "QUIT" + "\r\n", cset);
        if (rstr.StartsWith("2") == false)
        {
            throw new Exception("エラー:" + rstr);
        }
    }

    /// <summary>
    /// メールサーバとの送受信
    /// </summary>
    /// <param name="stm">メールサーバ通信ストリーム</param>
    /// <param name="req">リクエスト(コマンド)</param>
    /// <param name="cts">文字コード</param>
    /// <returns>レスポンス</returns>
    private String StreamWriteAndRead(
        System.Net.Security.SslStream stm, String req, String cst)
    {
        // メールサーバへリクエスト送信
        if (req != "")
        {
            Byte[] sdat;
            sdat = System.Text.Encoding.GetEncoding(cst).GetBytes(req);
            stm.Write(sdat, 0, sdat.Length);
            stm.Flush();
        }

        // メールサーバからのレスポンス受信
        String rstr = "";
        Byte[] rdat = new Byte[] { };
        Array.Resize<Byte>(ref rdat, 1024 * 1024);
        int l = stm.Read(rdat, 0, rdat.Length);
        if (l > 0)
        {
            Array.Resize<Byte>(ref rdat, l);
            rstr = System.Text.Encoding.GetEncoding(cst).GetString(rdat);
        }
        else
        {
            throw new Exception("Read Error.");
        }

        // レスポンス応答
        return rstr;
    }

    /// <summary>
    /// 指定文字コードのBASE64エンコード
    /// </summary>
    /// <param name="str">オリジナル文字列</param>
    /// <param name="cst">文字コード</param>
    /// <returns>エンコード結果文字列</returns>
    private String Enc_Base64_1(String str, String cst)
    {
        if (str == "") return "";
        System.Text.Encoding enc = System.Text.Encoding.GetEncoding(cst);
        return Convert.ToBase64String(enc.GetBytes(str));
    }

    /// <summary>
    /// 指定文字コードのBASE64エンコード
    /// </summary>
    /// <param name="str">オリジナル文字列</param>
    /// <param name="cst">文字コード</param>
    /// <returns>エンコード結果文字列</returns>
    /// <remarks>"=?ISO-2022-JP?B?"〜"?="フォーマット</remarks>
    private String Enc_Base64_2(String str, String cst)
    {
        if (str == "") return "";
        System.Text.Encoding enc = System.Text.Encoding.GetEncoding(cst);
        return "=?" + cst + "?B?" + Convert.ToBase64String(enc.GetBytes(str)) + "?=";
    }
}