diff --git a/AegisImplictMail/MimeAttachment.cs b/AegisImplictMail/MimeAttachment.cs index 5473fc8..c55cf80 100644 --- a/AegisImplictMail/MimeAttachment.cs +++ b/AegisImplictMail/MimeAttachment.cs @@ -2,6 +2,7 @@ using System.IO; using System.Net.Mail; using System.Net.Mime; +using System.Text; namespace AegisImplicitMail { @@ -16,9 +17,10 @@ public class MimeAttachment : Attachment internal static int AttachCount; private AttachmentLocation _location; /// - /// File to send. + /// Attachment is a File Stream /// - public string FileName { get; set; } + public bool isFileStream { get; private set; } = false; + /// /// Content type of file (application/octet-stream for regular attachments). /// @@ -48,74 +50,106 @@ public AttachmentLocation Location } } + public string GetEncodedAttachmentName() + { + Encoding displayNameEncoding = this.NameEncoding ?? Encoding.UTF8; + if (displayNameEncoding.Equals(Encoding.ASCII)) + { + return this.ContentType.Name; + } + else + { + string encodingName = displayNameEncoding.BodyName.ToLower(); + string encodedName = $"=?{encodingName}?B?{Convert.ToBase64String(displayNameEncoding.GetBytes(this.ContentType.Name))}?="; + return encodedName; + } + } + #endregion #region Constructors - /// - /// Default constructor. - /// - // public SmtpAttachment():base(){} /// - /// Constructor for passing all information at once. + /// Initializes a new instance of the AegisImplicitMail.MimeAttachment class with the specified + /// content string. /// - /// File to send. - /// Content type of file (application/octet-stream for regular attachments.) - /// Where to put the attachment. - public MimeAttachment(string fileName, ContentType contentType, AttachmentLocation location) + /// A System.String that contains a file path to use to create this attachment + /// Attached or Inline + public MimeAttachment(string fileName, AttachmentLocation location = AttachmentLocation.Attachmed) : base(fileName) { - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentException(nameof(fileName)); - } - FileName = fileName; - ContentType = contentType; Location = location; } + /// + /// Initializes a new instance of the AegisImplicitMail.MimeAttachment class with the specified + /// content string and System.Net.Mime.ContentType. + /// + /// A System.String that contains a file path to use to create this attachment. + /// A System.Net.Mime.ContentType that describes the data in string. + /// Attached or Inline + public MimeAttachment(string fileName, ContentType contentType, AttachmentLocation location = AttachmentLocation.Attachmed) + : base(fileName, contentType) + { + Location = location; + } /// - /// Shortcut constructor for passing regular style attachments. + /// Initializes a new instance of the AegisImplicitMail.MimeAttachment class with the specified + /// stream and name. /// - /// File to send. - public MimeAttachment(string filename) - : this(filename, new ContentType(MediaTypeNames.Application.Octet), AttachmentLocation.Attachmed) + /// A readable System.IO.Stream that contains the content for this attachment. + /// + /// A System.String that contains the value for the System.Net.Mime.ContentType.Name + /// property of the System.Net.Mime.ContentType associated with this attachment. + /// To ensure compatibility with the most number of email providers, this value cannot be null. + /// + /// Attached or Inline + public MimeAttachment(Stream contentStream, string name, AttachmentLocation location = AttachmentLocation.Attachmed) + : base(contentStream, name) { + isFileStream = true; + Location = location; } /// - /// Constructor for passing stream attachments. + /// Initializes a new instance of the AegisImplicitMail.MimeAttachment class with the specified + /// stream and content type. /// - /// Stream to the attachment contents - /// Name of the attachment as it will appear on the e-mail - /// Where to put the attachment - public MimeAttachment(Stream contentStream, string name, AttachmentLocation location = AttachmentLocation.Attachmed) - :this(contentStream, name, new ContentType(MediaTypeNames.Application.Octet), location) + /// A readable System.IO.Stream that contains the content for this attachment. + /// A System.Net.Mime.ContentType that describes the data in stream. + /// Attached or Inline + public MimeAttachment(Stream contentStream, ContentType contentType, AttachmentLocation location = AttachmentLocation.Attachmed) + :base(contentStream, contentType) { + isFileStream = true; + Location = location; } /// /// Constructor for passing stream attachments. + /// This constructor has no equivalent in System.Net.Mail.Attachment constructors. + /// Stays here for compatibility reasons. /// /// Stream to the attachment contents /// Name of the attachment as it will appear on the e-mail /// Content type of the attachment - /// Where to put the attachment + /// Attached or Inline public MimeAttachment(Stream contentStream, string name, ContentType contentType, AttachmentLocation location = AttachmentLocation.Attachmed) - : base(contentStream, name) + : this(contentStream, name) { + isFileStream = true; Location = location; - ContentType = contentType; + ContentType.Name = name; } /// /// Show this attachment. /// - /// The file name of the attachment. + /// The name of the attachment. public override string ToString() { - return FileName; + return this.ContentType.Name; } } diff --git a/AegisImplictMail/SmtpSocketClient.cs b/AegisImplictMail/SmtpSocketClient.cs index 4c76a48..2d5d883 100644 --- a/AegisImplictMail/SmtpSocketClient.cs +++ b/AegisImplictMail/SmtpSocketClient.cs @@ -1092,38 +1092,19 @@ private void SendAttachments(StringBuilder buf, AttachmentLocation type) continue; } - Stream stream; - string fileName; - if (string.IsNullOrEmpty(attachment.FileName)) - { - stream = attachment.ContentStream; - fileName = attachment.Name; - } - else - { - stream = new FileStream(attachment.FileName, FileMode.Open, FileAccess.Read, FileShare.Read); - fileName = Path.GetFileName(attachment.FileName); - } - - var cs = new CryptoStream(stream, new ToBase64Transform(), CryptoStreamMode.Read); + var cs = new CryptoStream(attachment.ContentStream, new ToBase64Transform(), CryptoStreamMode.Read); _con.SendCommand(seperator); - var escapedFileName = fileName.Replace(@"\", @"\\").Replace(@"""", @"\"""); buf.Append("Content-Type: "); buf.Append(attachment.ContentType); - buf.Append("; name=\""); - buf.Append(escapedFileName); - buf.Append("\""); _con.SendCommand(buf.ToString()); _con.SendCommand("Content-Transfer-Encoding: base64"); buf.Length = 0; - buf.Append("Content-Disposition: attachment; filename=\""); - buf.Append(escapedFileName); - buf.Append("\""); + buf.Append("Content-Disposition: attachment; filename="); + buf.Append(attachment.GetEncodedAttachmentName()); _con.SendCommand(buf.ToString()); buf.Length = 0; buf.Append("Content-ID: "); - var escapedContentId = "<" + (!string.IsNullOrEmpty(attachment.ContentId) ? attachment.ContentId : Path.GetFileNameWithoutExtension(fileName).Replace(" ", "-")) + ">"; - buf.Append(escapedContentId); + buf.Append(attachment.ContentId); buf.Append("\r\n"); _con.SendCommand(buf.ToString()); buf.Length = 0;