Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Tagged as

Understanding the Insides of the SMTP Mail Protocol: Part 1

, 9 Dec 2012
This article describes the mail sending process using the SMTP mail protocol.
HigLaboSampleSource-noexe.zip
Source
HigLabo.Mail.SampleApplication
HigLabo.Mail.SampleApplication.suo
HigLabo.Mail.SampleApplication.v11.suo
Properties
HigLabo.Mail
Async
Common
HigLabo.Mail.csproj.user
HigLabo.Mail.csproj.vspscc
Imap
Command
Pop3
Command
Properties
Smtp
Command
SendMail
HigLabo.Net
Core
Extensions
HigLabo.Net.csproj.user
HigLabo.Net.csproj.vspscc
HigLabo.Net.Silverlight.csproj.user
HigLabo.Net.Silverlight.csproj.vspscc
HigLabo.Net.WindowsPhone7.csproj.user
HigLabo.Net.WindowsPhone7.csproj.vspscc
Http
OAuth
Properties
Socket
HigLaboSampleSource.zip
bin
Release
HigLabo.Mail.dll
HigLabo.Mail.SampleApplication.exe
HigLabo.Net.dll
Newtonsoft.Json.dll
HigLabo.Mail.SampleApplication.suo
HigLabo.Mail.SampleApplication.v11.suo
bin
Release
HigLabo.Mail.dll
HigLabo.Net.dll
Newtonsoft.Json.dll
HigLabo.Mail.csproj.user
HigLabo.Mail.csproj.vspscc
bin
Release
de
System.Xml.Linq.resources.dll
es
System.Xml.Linq.resources.dll
fr
System.Xml.Linq.resources.dll
HigLabo.Net.dll
HigLabo.Net.Silverlight.dll
HigLabo.Net.WindowsPhone7.dll
it
System.Xml.Linq.resources.dll
ja
System.Xml.Linq.resources.dll
ko
System.Xml.Linq.resources.dll
Newtonsoft.Json.dll
Newtonsoft.Json.Silverlight.dll
Newtonsoft.Json.WindowsPhone7.dll
ru
System.Xml.Linq.resources.dll
System.Xml.Linq.dll
zh-Hans
System.Xml.Linq.resources.dll
zh-Hant
System.Xml.Linq.resources.dll
HigLabo.Net.csproj.user
HigLabo.Net.csproj.vspscc
HigLabo.Net.Silverlight.csproj.user
HigLabo.Net.Silverlight.csproj.vspscc
HigLabo.Net.WindowsPhone7.csproj.user
HigLabo.Net.WindowsPhone7.csproj.vspscc
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using HigLabo.Net.Mail;

namespace HigLabo.Net.Smtp
{
    /// Represent smtp content.
    /// <summary>
    /// Represent smtp content.
    /// </summary>
    public class SmtpContent : MimeContent
    {
        private FieldParameterEncoding _FieldParameterEncoding = FieldParameterEncoding.Rfc2047;
        private List<SmtpContent> _Contents;
        private static Dictionary<String, String> FileExtensionContentType = new Dictionary<String, String>();
        private String _BodyText = "";
        /// HeaderのFieldのParameterのEncodingを取得または設定します。
        /// <summary>
        /// HeaderのFieldのParameterのEncodingを取得または設定します。
        /// </summary>
        public FieldParameterEncoding FieldParameterEncoding
        {
            get { return this._FieldParameterEncoding; }
            set { this._FieldParameterEncoding = value; }
        }
        /// Nameの値を取得または設定します。
        /// <summary>
        /// Nameの値を取得または設定します。
        /// </summary>
        public String Name
        {
            get { return this.ContentType.Name; }
            set { this.ContentType.Name = value; }
        }
        /// FileNameの値を取得または設定します。
        /// <summary>
        /// FileNameの値を取得または設定します。
        /// </summary>
        public String FileName
        {
            get { return this.ContentDisposition.FileName; }
            set { this.ContentDisposition.FileName = value; }
        }
        /// ボディ部分のテキスト文字列を取得または設定します。
        /// <summary>
        /// ボディ部分のテキスト文字列を取得または設定します。
        /// </summary>
        public String BodyText
        {
            get { return this._BodyText; }
            private set { this._BodyText = value; }
        }
        /// SmtpContentのコレクションを取得します。
        /// <summary>
        /// SmtpContentのコレクションを取得します。
        /// </summary>
        public new List<SmtpContent> Contents
        {
            get { return this._Contents; }
        }
        static SmtpContent()
        {
            SmtpContent.InitializeFileExtenstionContentType();
        }
		/// <summary>
		/// 
		/// </summary>
		public SmtpContent() :
			base()
		{
            this.ContentTransferEncoding = TransferEncoding.Base64;
            this._Contents = new List<SmtpContent>();
		}
        /// 拡張子とContent-Typeのマッピングのデータを初期化します。
        /// <summary>
        /// 拡張子とContent-Typeのマッピングのデータを初期化します。
        /// </summary>
        private static void InitializeFileExtenstionContentType()
        {
            var l = SmtpContent.FileExtensionContentType;
            l.Add("txt", "text/plain");
            l.Add("css", "text/css");
            l.Add("htm", "text/html");
            l.Add("html", "text/html");
            l.Add("jpg", "Image/jpeg");
            l.Add("gif", "Image/gif");
            l.Add("bmp", "image/x-ms-bmp");
            l.Add("png", "Image/png");
            l.Add("wav", "Audio/wav");
            l.Add("doc", "application/msword");
            l.Add("mdb", "application/msaccess");
            l.Add("xls", "application/vnd.ms-excel");
            l.Add("ppt", "application/vnd.ms-powerpoint");
            l.Add("mpeg", "video/mpeg");
            l.Add("mpg", "video/mpeg");
            l.Add("avi", "video/x-msvideo");
            l.Add("zip", "application/zip");
        }
        /// 拡張子を元にContent-Typeの文字列を取得します。
        /// <summary>
        /// 拡張子を元にContent-Typeの文字列を取得します。
        /// </summary>
        /// <param name="extension"></param>
        /// <returns></returns>
        private static String GetContentType(String extension)
        {
            String s = extension.Replace(".", "").ToLower();
            if (SmtpContent.FileExtensionContentType.ContainsKey(s.ToLower()) == true)
            {
                return SmtpContent.FileExtensionContentType[s.ToLower()];
            }
            return "application/octet-stream";
        }
        /// 指定したテキストデータをセットします。
        /// <summary>
        /// 指定したテキストデータをセットします。
        /// </summary>
        /// <param name="text"></param>
        public void LoadText(String text)
        {
            this.ContentType.Value = "text/plain";
            this.BodyText = text;
            this.SetData();
        }
        /// HTML形式のテキストをセットします。
        /// <summary>
        /// HTML形式のテキストをセットします。
        /// </summary>
        /// <param name="html"></param>
        public void LoadHtml(String html)
        {
            this.ContentType.Value = "text/html";
            this.BodyText = html;
            this.SetData();
        }
        /// 指定したファイルパスのファイルデータを元にデータをセットします。
        /// <summary>
        /// 指定したファイルパスのファイルデータを元にデータをセットします。
        /// </summary>
        /// <param name="filePath"></param>
        public void LoadFileData(String filePath)
        {
            FileInfo fi = null;
            Byte[] b = null;

            fi = new FileInfo(filePath);

            this.ContentType.Value = SmtpContent.GetContentType(Path.GetExtension(filePath).Replace(".", ""));
            this.ContentType.Name = fi.Name;
            this.ContentDisposition.FileName = fi.Name;
            this.ContentDisposition.Value = "attachment";

            b = new Byte[fi.Length];
            using (var stm = new FileStream(filePath, FileMode.Open))
            {
                stm.Read(b, 0, b.Length);
                this.BodyText = Convert.ToBase64String(b);
                stm.Close();
            }
            this.SetData();
        }
        /// バイトデータを元にデータをセットします。
        /// <summary>
        /// バイトデータを元にデータをセットします。
        /// </summary>
        /// <param name="bytes"></param>
        public void LoadData(Byte[] bytes)
        {
            this.ContentDisposition.Value = "attachment";
            this.ContentTransferEncoding = TransferEncoding.Base64;
            this.BodyText = Convert.ToBase64String(bytes);
            this.SetData();
        }
        private void SetData()
        {
            this.SetHeaderData();
            this.SetBodyData();
            this.Data = this.HeaderData + MailParser.NewLine + this.BodyData;
        }
        private void SetHeaderData()
        {
            StringBuilder sb = new StringBuilder(1024);

            if (this.IsMultiPart == false &&
                this.Contents.Count > 0)
            {
                this.ContentType.Value = "multipart/mixed";
            }
            if (this.IsBody == true)
            {
                sb.AppendFormat("Content-Type: {0}; charset=\"{1}\"", this.ContentType.Value, this.ContentEncoding.WebName);
                sb.Append(MailParser.NewLine);
            }
            else
            {
                sb.AppendFormat("Content-Type: {0};", this.ContentType.Value);
                sb.Append(MailParser.NewLine);
                if (String.IsNullOrEmpty(this.ContentType.Name) == false)
                {
                    if (this._FieldParameterEncoding == Mail.FieldParameterEncoding.Rfc2047)
                    {
                        sb.AppendFormat(" name=\"{0}\"", MailParser.EncodeToMailHeaderLine(this.ContentType.Name
                            , this.ContentTransferEncoding, this.ContentEncoding, MailParser.MaxCharCountPerRow - 8));
                    }
                    else if (this._FieldParameterEncoding == Mail.FieldParameterEncoding.Rfc2231)
                    {
                        sb.AppendFormat(MailParser.EncodeToMailHeaderLineByRfc2231("name", this.ContentType.Name
                            , this.ContentEncoding, MailParser.MaxCharCountPerRow - 8));
                    }
                    sb.Append(MailParser.NewLine);
                }
            }
            sb.AppendFormat("Content-Transfer-Encoding: {0}", MailParser.ToTransferEncoding(this.ContentTransferEncoding));
            sb.Append(MailParser.NewLine);
            if (String.IsNullOrEmpty(this["Content-Disposition"]) == false)
            {
                sb.AppendFormat("Content-Disposition: {0};", this.ContentDisposition.Value);
                sb.Append(MailParser.NewLine);
                if (String.IsNullOrEmpty(this.ContentDisposition.FileName) == false)
                {
                    if (this._FieldParameterEncoding == Mail.FieldParameterEncoding.Rfc2047)
                    {
                        sb.AppendFormat(" filename=\"{0}\"", MailParser.EncodeToMailHeaderLine(this.ContentDisposition.FileName
                            , this.ContentTransferEncoding, this.ContentEncoding, MailParser.MaxCharCountPerRow - 12));
                    }
                    else if (this._FieldParameterEncoding == Mail.FieldParameterEncoding.Rfc2231)
                    {
                        sb.AppendFormat(MailParser.EncodeToMailHeaderLineByRfc2231("filename", this.ContentDisposition.FileName
                            , this.ContentEncoding, MailParser.MaxCharCountPerRow - 12));
                    }
                    sb.Append(MailParser.NewLine);
                }
            }
            if (String.IsNullOrEmpty(this["Content-Description"]) == false)
            {
                sb.AppendFormat("Content-Description: {0}", this["Content-Description"]);
                sb.Append(MailParser.NewLine);
            }
            this.HeaderData = sb.ToString();
        }
        private void SetBodyData()
        {
            StringBuilder sb = new StringBuilder(1024);
            String bodyText = "";

            if (this.IsMultiPart == true)
            {
                for (int i = 0; i < this._Contents.Count; i++)
                {
                    sb.Append("--");
                    sb.Append(this.MultiPartBoundary);
                    sb.Append(MailParser.NewLine);
                    sb.Append(this._Contents[i].Data);
                    sb.Append(MailParser.NewLine);
                }
                sb.AppendFormat("--{0}--", this.MultiPartBoundary);
            }
            else
            {
                if (this.IsAttachment == true)
                {
                    bodyText = this.BodyText;
                }
                else
                {
                    bodyText = MailParser.EncodeToMailBody(this.BodyText, this.ContentTransferEncoding, this.ContentEncoding);
                }
                if (this.ContentTransferEncoding == TransferEncoding.SevenBit)
                {
                    sb.Append(bodyText);
                }
                else
                {
                    for (int i = 0; i < bodyText.Length; i++)
                    {
                        if (i > 0 &&
                            i % 76 == 0)
                        {
                            sb.Append(MailParser.NewLine);
                        }
                        sb.Append(bodyText[i]);
                    }
                }
            }
            this.BodyData = sb.ToString();
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Higty
Web Developer
Japan Japan
I'm Working at Software Company in Tokyo.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 10 Dec 2012
Article Copyright 2012 by Higty
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid