Ejemplo n.º 1
0
        //DATAコマンドを送る
        private void SendDataCommand(MailParameters mailParams)
        {
            //送信データを作成する
            string data = CreateSendStringDataFromMessage(mailParams);

            // データコマンド送信
            var code = SmtpSendAndReceive("DATA\r\n");

            if (code != 354)
            {
                throw new SmtpException(smtpcom.received);
            }

            // データ本体送信
            code = SmtpSendAndReceive(data);
            if (code != 250)
            {
                throw new SmtpException(smtpcom.received);
            }
        }
Ejemplo n.º 2
0
        private void PopBeforeSmtp(MailParameters mailParams)
        {
            Stream stream = null;

            System.Net.Sockets.TcpClient popclient = null;
            try
            {
                string rstr;
                popclient = new System.Net.Sockets.TcpClient();

                // POPサーバーに接続
                popclient.Connect(mailParams.PopServer, mailParams.PopPort);
                logs.AppendLine("POP: Connected.");

                X509CertificateCollection clientCertificateCollection = new X509CertificateCollection();
                if (mailParams.IsClientCertValidate)
                {
                    var clientCertificate = Cert.GetCert(mailParams.ClientCertSerialNo);
                    clientCertificateCollection.Add(clientCertificate);
                }

                // サーバーとデータの送受信を行うストリームを取得する
                // 通信開始(SSL有り)
                switch (mailParams.PopSecureMode)
                {
                case SecureMode.SSL2:                   // SSL2で運用しているサーバは存在しないはずだが、一応対応しておく
                    stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation);
                    ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl2, false);
                    logs.AppendLine("POP: socket is over SSL2.");
                    break;

                case SecureMode.SSL3:                   // SSL3で運用しているサーバはあるかもしれない
                    stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation);
                    ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl3, false);
                    logs.AppendLine("POP: socket is over SSL3.");
                    break;

                case SecureMode.TLS:                    // TLSは現状では主流
                case SecureMode.STARTTLS:
                    stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation);
                    ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Tls, false);

                    logs.AppendLine("POP: socket is over TLS.");
                    break;

                case SecureMode.None:
                    stream = popclient.GetStream();
                    logs.AppendLine("POP: socket unsecure.");
                    break;
                }
                stream.ReadTimeout  = 5000;
                stream.WriteTimeout = 500;

                //サーバーからのはじめのメッセージを受信

                // POPサーバー接続時のレスポンス受信
                string connectstr = PopWriteAndRead(stream, "");
                if (connectstr.StartsWith("+OK") != true)
                {
                    throw new PopException("POPサーバー接続エラー");
                }

                switch (mailParams.PopAuth)
                {
                case PopAuthMethod.Standard:
                    // ユーザIDの送信
                    rstr = PopWriteAndRead(stream, "USER " + mailParams.PopUserId + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("ユーザIDエラー");
                    }

                    // パスワードの送信
                    rstr = PopWriteAndRead(stream, "PASS " + mailParams.PopPasswd + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("パスワードエラー");
                    }
                    break;

                case PopAuthMethod.APOP:
                    // APOP用のタイムスタンプ文字列を取得しておく
                    var timestamp = GetAPopTimeStamp(connectstr);
                    if (string.IsNullOrWhiteSpace(timestamp))
                    {
                        throw new PopException("APOP未対応");
                    }
                    Byte[] byt = System.Text.Encoding.ASCII.GetBytes(string.Format("<{0}>{1}", mailParams.PopUserId, mailParams.PopPasswd));
                    System.Security.Cryptography.MD5CryptoServiceProvider md5 =
                        new System.Security.Cryptography.MD5CryptoServiceProvider();
                    Byte[] res = md5.ComputeHash(byt);
                    string aps = BitConverter.ToString(res).Replace("-", "").ToLower();
                    rstr = PopWriteAndRead(stream, "APOP " + mailParams.PopUserId + " " + aps + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("ユーザIDまたはパスワードエラー");
                    }
                    break;

                case PopAuthMethod.NTLM:
                    // ユーザIDの送信
                    rstr = PopWriteAndRead(stream, "USER " + mailParams.PopUserId + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("ユーザIDエラー");
                    }

                    // パスワードの送信
                    rstr = PopWriteAndRead(stream, "PASS " + mailParams.PopPasswd + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("パスワードエラー");
                    }
                    break;

                case PopAuthMethod.CramMd5:
                    rstr = PopWriteAndRead(stream, "AUTH CRAM-MD5\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("CRAM-MD5未対応");
                    }

                    rstr = PopWriteAndRead(stream, CreateCramMd5ResponseString(rstr.Substring(4), mailParams.PopUserId, mailParams.PopPasswd) + "\r\n");
                    if (rstr.StartsWith("+OK") != true)
                    {
                        throw new PopException("認証エラー");
                    }
                    break;
                }

                // ステータスの送信
                rstr = PopWriteAndRead(stream, "STAT" + "\r\n");
                if (rstr.StartsWith("+OK") != true)
                {
                    throw new PopException("STATエラー");
                }

                // 終了の送信
                rstr = PopWriteAndRead(stream, "QUIT" + "\r\n");
                // 戻り値は無視
            }
            catch (PopException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw new PopException("内部例外発生", ex);
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                    stream.Dispose();
                }
                if (popclient != null)
                {
                    popclient.Close();
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// メール送信データ編集(ヘッダ&ボディ)
        /// </summary>
        /// <param name="mailParams"></param>
        /// <returns></returns>
        private string CreateSendStringDataFromMessage(MailParameters mailParams)
        {
            StringBuilder data = new StringBuilder();

            // ヘッダ部
            data.Append("From: ").Append(mailParams.From.Trim()).Append("\r\n");
            string prefix;

            if (mailParams.To != null && mailParams.To.Length > 0)
            {
                prefix = "To: ";
                foreach (var to in mailParams.To)
                {
                    data.Append(prefix).Append(to.Trim());
                    prefix = ",";
                }
                data.Append("\r\n");
            }
            if (mailParams.Cc != null && mailParams.Cc.Length > 0)
            {
                prefix = "Cc: ";
                foreach (var cc in mailParams.Cc)
                {
                    data.Append(prefix).Append(cc.Trim());
                    prefix = ",";
                }
                data.Append("\r\n");
            }
            // Bccは送信しても消されるので編集すること自体が無意味(RCPT TOコマンドで送信済み)

            // ReplyTo
            if (string.IsNullOrWhiteSpace(mailParams.ReplyTo) != true)
            {
                data.Append("ReplyTo: ").Append(mailParams.ReplyTo.Trim()).Append("\r\n");
            }
            // Sender
            if (string.IsNullOrWhiteSpace(mailParams.Sender) != true)
            {
                data.Append("Sender: ").Append(mailParams.Sender.Trim()).Append("\r\n");
            }
            if (mailParams.ExtHeaders != null)
            {
                foreach (var ext in mailParams.ExtHeaders)
                {
                    if (string.IsNullOrWhiteSpace(ext))
                    {
                        // 空文字は無視
                        continue;
                    }
                    if (ext.StartsWith("X-") != true || ext.Contains(": ") != true)
                    {
                        throw new SmtpException("Invalid format in Optional-header[" + ext + "]");
                    }
                    data.Append(ext + "\r\n");
                }
            }

            //件名をBase64でエンコード
            data.Append("Subject: =?" + _encoding.BodyName + "?B?").Append(GetBase64String(mailParams.Subject)).Append("?=").Append("\r\n");
            data.Append("MIME-Version: 1.0\r\n");
            data.Append("Content-Transfer-Encoding: 7bit\r\n");
            if (mailParams.Files == null || mailParams.Files.Length == 0)
            {
                // 添付ファイルがない場合(テキスト本文のみ)
                data.Append("Content-Type: text/plain; charset=" + _encoding.BodyName + "\r\n");
                // ヘッダとボディの区切りのための改行
                data.Append("\r\n");
                // ボディ部
                data.Append(mailParams.Body.Replace("\r\n.\r\n", "\r\n..\r\n"));
            }
            else
            {
                string boundary = string.Empty;
                {
                    // boundary文字列を乱数から生成(まともな乱数にするため、System.Randomは使用禁止)
                    System.Security.Cryptography.RNGCryptoServiceProvider rnd = new System.Security.Cryptography.RNGCryptoServiceProvider();
                    byte[] bytes = new byte[24];
                    rnd.GetBytes(bytes);
                    boundary = "_PART_" + Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
                }
                // 注意:boundaryの文字列は""で囲むのがRFC的に正しい。
                data.Append("Content-Type: multipart/mixed; boundary=\"" + boundary + "\"\r\n");
                // ヘッダとボディの区切りのための改行
                data.Append("\r\n");
                // 本文は textパート
                data.Append("--" + boundary + "\r\n");
                data.Append("Content-Type: text/plain; charset=" + _encoding.BodyName + "\r\n");
                data.Append("\r\n");
                data.Append(mailParams.Body.Replace("\r\n.\r\n", "\r\n..\r\n"));

                // 添付ファイル
                foreach (var file in mailParams.Files)
                {
                    FileInfo   fi = new FileInfo(file);
                    byte[]     fdata;
                    FileStream fs     = new FileStream(file, FileMode.Open);
                    long       length = fs.Length;
                    if (length > int.MaxValue)
                    {
                        fs.Dispose();
                        throw new SmtpException("too large file");
                    }
                    else
                    {
                        fdata = new byte[length];
                        fs.Read(fdata, 0, (int)length);
                        fs.Dispose();
                    }
                    string b64  = "Content-type: unknown;\r\n";
                    string fstr = Convert.ToBase64String(_encoding.GetBytes(fi.Name), Base64FormattingOptions.InsertLineBreaks);
                    b64 += " name=" + "=?ISO-2022-JP?B?" + fstr + "?=" + "\r\n";
                    b64 += "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n";
                    b64 += " filename=" + "=?ISO-2022-JP?B?" + fstr + "?=" + "\r\n\r\n";
                    {
                        b64 += Convert.ToBase64String(fdata, Base64FormattingOptions.InsertLineBreaks);
                    }
                    data.Append("\r\n\r\n--" + boundary + "\r\n");
                    data.Append(b64);
                }
                // multipart の終端
                data.Append("\r\n\r\n--" + boundary + "--\r\n");
            }

            // メールデータの終端
            data.Append("\r\n.\r\n");

            return(data.ToString());
        }
Ejemplo n.º 4
0
        /// <summary>
        /// SMTPサーバーと接続する
        /// </summary>
        private SmtpCommData SmtpConnect(MailParameters mailParams)
        {
            this.IsServerCertValidate = mailParams.IsServerCertValidate;
            smtpcom = new SmtpCommData();

            smtpcom.socket = new TcpClient();

            // SMTPサーバーと接続する
            smtpcom.socket.Connect(mailParams.SmtpServer, mailParams.SmtpPort);
            logs.AppendLine("SMTP: Connected.");

            X509CertificateCollection clientCertificateCollection = new X509CertificateCollection();

            if (mailParams.IsClientCertValidate)
            {
                var clientCertificate = Cert.GetCert(mailParams.ClientCertSerialNo);
                clientCertificateCollection.Add(clientCertificate);
            }

            // サーバーとデータの送受信を行うストリームを取得する
            // 通信開始(SSL有り)
            switch (mailParams.SmtpSecureMode)
            {
            case SecureMode.SSL2:               // SSL2で運用しているサーバは存在しないはずだが、一応対応しておく
                smtpcom.stream = new System.Net.Security.SslStream(smtpcom.socket.GetStream(), false, ServerCertificateValidation);
                ((System.Net.Security.SslStream)smtpcom.stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl2, false);
                logs.AppendLine("SMTP: socket is over SSL2.");
                break;

            case SecureMode.SSL3:               // SSL3で運用しているサーバはあるかもしれない
                smtpcom.stream = new System.Net.Security.SslStream(smtpcom.socket.GetStream(), false, ServerCertificateValidation);
                ((System.Net.Security.SslStream)smtpcom.stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl3, false);
                logs.AppendLine("SMTP: socket is over SSL3.");
                break;

            case SecureMode.TLS:                // TLSは現状では主流
            case SecureMode.STARTTLS:
                smtpcom.stream = new System.Net.Security.SslStream(smtpcom.socket.GetStream(), false, ServerCertificateValidation);
                ((System.Net.Security.SslStream)smtpcom.stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Tls, false);

                logs.AppendLine("SMTP: socket is over TLS.");
                break;

            case SecureMode.None:
                smtpcom.stream = smtpcom.socket.GetStream();
                logs.AppendLine("SMTP: socket unsecure.");
                break;
            }
            smtpcom.stream.ReadTimeout  = 5000;
            smtpcom.stream.WriteTimeout = 500;
            smtpcom.reader = new System.IO.StreamReader(smtpcom.stream, _encoding);
            smtpcom.writer = new System.IO.StreamWriter(smtpcom.stream, _encoding);

            //サーバーからのはじめのメッセージを受信
            var ret = ReceiveData();

            if (ret != 220)
            {
                throw new SmtpException(smtpcom.received);
            }

            return(smtpcom);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// 指定されたパラメータの内容でメールを送信する(エンコードはISO-2022-JPのみをサポート)
        /// </summary>
        /// <param name="mailParams">メール送信パラメータ</param>
        /// <returns>送信結果(true:正常、false:失敗)</returns>
        public bool SendMail(MailParameters mailParams)
        {
            // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
            // ■
            // ■ System.Net.Mail.SmtpClient は、SMTP.SSLに対応していないため使用不可なので、
            // ■ いろんなパターンに対応するため、TcpClientを使ってプロトコルを実装する。
            // ■
            // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

            bool result = false;

            mailParams.logs = string.Empty;
            try
            {
                // ISO-2022-JPでエンコードする
                _encoding = System.Text.Encoding.GetEncoding(50220);

                if (mailParams.IsPopBeforeSmtp)
                {
                    // POP before SMTP 指定の場合
                    PopBeforeSmtp(mailParams);
                    if (mailParams.PopDelayTime > 0)
                    {
                        System.Threading.Thread.Sleep(mailParams.PopDelayTime);
                    }
                }

                // SMTPサーバーと接続する
                smtpcom = SmtpConnect(mailParams);

                // EHLO
                SendHeloCommand(System.Net.Dns.GetHostName());

                if (mailParams.SmtpSecureMode == SecureMode.STARTTLS)
                {
                    // TLSの実装------------------------------------------------------------------
                    // STARTTLSの送信
                    var rcode = SmtpSendAndReceive("STARTTLS" + "\r\n");
                    if ((rcode / 100) != 2)
                    {
                        throw new SmtpException("エラー:" + rcode);
                    }

                    // SSLの開始
                    smtpcom.stream = new System.Net.Security.SslStream(smtpcom.socket.GetStream());
                    ((System.Net.Security.SslStream)smtpcom.stream).AuthenticateAsClient(mailParams.SmtpServer);
                    smtpcom.stream.ReadTimeout  = 5000;
                    smtpcom.stream.WriteTimeout = 500;
                    smtpcom.reader = new System.IO.StreamReader(smtpcom.stream, _encoding);
                    smtpcom.writer = new System.IO.StreamWriter(smtpcom.stream, _encoding);
                }


                // AUTH
                Authenticate(mailParams.SmtpAuth, mailParams.SmtpUserId, mailParams.SmtpPasswd);
                // MAIL FROM(RCPTより先に送信する)
                SendMailFromCommand(mailParams.From);
                // RCPT TO
                SendRcptToCommand(mailParams.To, mailParams.Cc, mailParams.Bcc);
                // DATA(メールヘッダ&ボディ)
                SendDataCommand(mailParams);

                // QUIT
                SendQuitCommand();

                result            = true;
                mailParams.status = "OK";
            }
            catch (Exception ex)
            {
                mailParams.status = "NG : " + ex.Message + ((ex.InnerException == null) ? "" : ("\r\n" + ex.InnerException.Message));
                result            = false;
            }
            finally
            {
                if (smtpcom != null)
                {
                    if (smtpcom.socket != null)
                    {
                        smtpcom.socket.Close();
                    }
                }
            }
            mailParams.logs = logs.ToString();
            return(result);
        }