2017年04月20日
川俣晶の縁側ソフトウェア技術雑記 total 8676 count

Mailkitを使用してSSL+POP before SMTPで添付ファイル付き電子メールを送信する (C#)

Written By: 川俣 晶連絡先

「Mailkitを使用してSSL+POP before SMTPで添付ファイル付き電子メールを送信するコードを書いたので、核心部分だけ公開」

「なぜ書いたのだ?」

「ソースの後で触れる」

ソースコード §

        public static void Send(string sendto, string sendfrom, string subject, string body,

            string[] attachFileNames,

            string smtpServerHostName, int smtpPort,

            string smtpUserId, string smtpUserPassword,

            string popServerHostName, int popPort,

            string popUserId, string popUserPassword)

        {

            if (isDisable(sendto)) return;

            if (isDisable(sendfrom)) return;

            if (isDisable(smtpServerHostName)) return;

            if (smtpPort == 0) return;

            bool useSmtpAuth = !isDisable(smtpUserId) && !isDisable(smtpUserPassword);

            bool usePopBeforeSmpt = !isDisable(popServerHostName) && popPort != 0

                && !isDisable(popUserId) && !isDisable(popUserPassword);

            var message = new MimeMessage();

            message.From.Add(new MailboxAddress(sendfrom));

            message.To.Add(new MailboxAddress(sendto));

            message.Subject = subject;

            if (attachFileNames.Length == 0)

            {

                message.Body = new TextPart("plain") { Text = body };

            }

            else

            {

                var multi = new Multipart();

                multi.Add(new TextPart("plain") { Text = body });

                foreach (var filename in attachFileNames)

                {

                    var attachment = new MimePart()

                    {

                        ContentObject = new ContentObject(File.OpenRead(filename), ContentEncoding.Default),

                        ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),

                        ContentTransferEncoding = ContentEncoding.Base64,

                        FileName = Path.GetFileName(filename)

                    };

                    multi.Add(attachment);

                }

                message.Body = multi;

            }

            if (usePopBeforeSmpt)

            {

                using (var client = new Pop3Client())

                {

                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                    client.Connect(popServerHostName, popPort, true);

                    client.AuthenticationMechanisms.Remove("XOAUTH2");

                    client.Authenticate(popUserId, popUserPassword);

                    client.Disconnect(true);

                }

            }

            using (var client = new SmtpClient())

            {

                client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                client.Connect(smtpServerHostName, smtpPort, true);

                client.AuthenticationMechanisms.Remove("XOAUTH2");

                client.Authenticate(smtpUserId, smtpUserPassword);

                client.Send(message);

                client.Disconnect(true);

            }

        }

経緯の説明 §

「実は.NET Frameworkの電子メール送信関係のクラスを見ている時、特に問題は無かったのだがMailkitを使ってね(英文の大意)という記述を発見してね。でも、問題は無いから無視しようと思った。ところが、問題ないというのは錯覚で実際は問題があった」

「どんな問題?」

「POP Before SMTPが必要とされていた」

「電子メールの送信クラスはPOPを叩けないね」

「だから、一気にMailkitにジャンプしたってわけだ。Mailkitそのものはnugetですぐ入る」

「それで、【SSL】【SMTPAuth】【POP before SMTP】を全部解決したわけだね?」

「そうだ。これで自社のクラウド上のメールサーバからダイレクトにメールを送れるようになった」

「もうローカル環境に非暗号化認証不要のSMTPサーバは無いんだね」

「無いよ。とっくに引退済みだ」

「これで問題は完全に解決?」

「あ、このソースだと接続先相手の妥当性をちゃんと検証してないから、そこは注意が必要だぞ」