/// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="emailAccount">Email account to use</param>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="fromAddress">From address</param>
        /// <param name="fromName">From display name</param>
        /// <param name="toAddress">To address</param>
        /// <param name="toName">To display name</param>
        /// <param name="replyTo">ReplyTo address</param>
        /// <param name="replyToName">ReplyTo display name</param>
        /// <param name="bcc">BCC addresses list</param>
        /// <param name="cc">CC addresses list</param>
        /// <param name="attachmentFilePath">Attachment file path</param>
        /// <param name="attachmentFileName">Attachment file name. If specified, then this file name will be sent to a recipient. Otherwise, "AttachmentFilePath" name will be used.</param>
        /// <param name="attachedDownloadId">Attachment download ID (another attachedment)</param>
        /// <param name="headers">Headers</param>
        public virtual void SendEmail(EmailAccount emailAccount, string subject, string body,
                                      string fromAddress, string fromName, string toAddress, string toName,
                                      string replyTo            = null, string replyToName = null,
                                      IEnumerable <string> bcc  = null, IEnumerable <string> cc           = null,
                                      string attachmentFilePath = null, string attachmentFileName         = null,
                                      int attachedDownloadId    = 0, IDictionary <string, string> headers = null)
        {
            //attachment support (v2.0 with attachment)
            var message = new MimeMessage();

            message.From.Add(new MailboxAddress(fromName, fromAddress));
            message.To.Add(new MailboxAddress(toName, toAddress));

            //reply to
            if (!string.IsNullOrEmpty(replyTo))
            {
                message.ReplyTo.Add(new MailboxAddress(replyTo));
            }

            //BCC
            if (bcc != null)
            {
                foreach (var address in bcc.Where(bccValue => !string.IsNullOrWhiteSpace(bccValue)))
                {
                    message.Bcc.Add(new MailboxAddress(address.Trim()));
                }
            }

            //CC
            if (cc != null)
            {
                foreach (var address in cc.Where(ccValue => !string.IsNullOrWhiteSpace(ccValue)))
                {
                    message.Cc.Add(new MailboxAddress(address.Trim()));
                }
            }

            if (headers != null)
            {
                foreach (var header in headers)
                {
                    message.Headers.Add(new Header(header.Key, header.Value));
                }
            }

            // Set the plain-text/html version of the message text
            var builder = new BodyBuilder
            {
                HtmlBody = body,
            };

            //build message
            message.Subject = subject;

            //create the file attachment for this e-mail message
            if (!string.IsNullOrEmpty(attachmentFilePath) &&
                File.Exists(attachmentFilePath))
            {
                // create a linked resource for attachment
                var resources = builder.LinkedResources.Add(attachmentFilePath);
                resources.ContentId = MimeUtils.GenerateMessageId();

                //add Attachments in body
                //builder.HtmlBody += $"<a href=\"{attachmentFilePath}\">{attachmentFileName}</a>";
            }

            //another attachment?
            if (attachedDownloadId > 0)
            {
                var download = _downloadService.GetDownloadById(attachedDownloadId);
                if (download != null)
                {
                    //we do not support URLs as attachments
                    if (!download.UseDownloadUrl)
                    {
                        var downloadFileName = !string.IsNullOrWhiteSpace(download.Filename) ? download.Filename : download.Id.ToString();
                        downloadFileName += download.Extension;

                        // create a linked resource for attachment
                        var resources = builder.LinkedResources.Add(downloadFileName, download.DownloadBinary, ContentType.Parse(download.ContentType));
                        resources.ContentId = MimeUtils.GenerateMessageId();

                        //add Attachments in body
                        //builder.HtmlBody += $"<a href=\"{downloadFileName}\">{downloadFileName}</a>";
                    }
                }
            }

            //build message
            message.Body = builder.ToMessageBody();

            //send email
            using (var client = new AmazonSimpleEmailServiceClient(_emailAccountSettings.AwsAccessId, _emailAccountSettings.AwsAccessKey, RegionEndpoint.USEast1))
            {
                try
                {
                    var stream = new MemoryStream();
                    message.WriteTo(stream);
                    var response = client.SendRawEmail(new SendRawEmailRequest()
                    {
                        RawMessage = new RawMessage()
                        {
                            Data = stream
                        }
                    });
                }
                catch (Exception ex)
                {
                    _logger.InsertLog(Core.Domain.Logging.LogLevel.Debug, "Error message: " + ex.Message);
                }
            }
        }
Example #2
0
        internal static bool TryParse(string text, ref int index, out Envelope envelope)
        {
            InternetAddressList from, sender, replyto, to, cc, bcc;
            string         inreplyto, messageid, subject, nstring;
            DateTimeOffset?date = null;

            envelope = null;

            while (index < text.Length && text[index] == ' ')
            {
                index++;
            }

            if (index >= text.Length || text[index] != '(')
            {
                if (index + 3 <= text.Length && text.Substring(index, 3) == "NIL")
                {
                    index += 3;
                    return(true);
                }

                return(false);
            }

            index++;

            if (!TryParse(text, ref index, out nstring))
            {
                return(false);
            }

            if (nstring != null)
            {
                DateTimeOffset value;

                if (!DateUtils.TryParse(nstring, out value))
                {
                    return(false);
                }

                date = value;
            }

            if (!TryParse(text, ref index, out subject))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out from))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out sender))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out replyto))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out to))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out cc))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out bcc))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out inreplyto))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out messageid))
            {
                return(false);
            }

            if (index >= text.Length || text[index] != ')')
            {
                return(false);
            }

            index++;

            envelope = new Envelope {
                Date      = date,
                Subject   = subject,
                From      = from,
                Sender    = sender,
                ReplyTo   = replyto,
                To        = to,
                Cc        = cc,
                Bcc       = bcc,
                InReplyTo = inreplyto != null?MimeUtils.EnumerateReferences(inreplyto).FirstOrDefault() ?? inreplyto : null,
                MessageId = messageid != null?MimeUtils.EnumerateReferences(messageid).FirstOrDefault() ?? messageid : null
            };

            return(true);
        }
Example #3
0
 /// <summary>
 /// Returns a <see cref="System.String"/> that represents the current
 /// <see cref="MimeKit.Parameter"/>.
 /// </summary>
 /// <returns>A <see cref="System.String"/> that represents the current
 /// <see cref="MimeKit.Parameter"/>.</returns>
 public override string ToString()
 {
     return(Name + "=" + MimeUtils.Quote(Value));
 }
        public void TestInvalidDoubleDomainMessageId()
        {
            var msgid = MimeUtils.EnumerateReferences("<local-part@domain1@domain2>").FirstOrDefault();

            Assert.AreEqual("local-part@domain1@domain2", msgid);
        }
Example #5
0
        /// <summary>
        /// Constructs the message body based on the text-based bodies, the linked resources, and the attachments.
        /// </summary>
        /// <remarks>
        /// Combines the <see cref="Attachments"/>, <see cref="LinkedResources"/>, <see cref="TextBody"/>,
        /// and <see cref="HtmlBody"/> into the proper MIME structure suitable for display in many common
        /// mail clients.
        /// </remarks>
        /// <returns>The message body.</returns>
        public MimeEntity ToMessageBody()
        {
            MultipartAlternative alternative = null;
            MimeEntity           body        = null;

            if (!string.IsNullOrEmpty(TextBody))
            {
                var text = new TextPart("plain");
                text.Text = TextBody;

                if (!string.IsNullOrEmpty(HtmlBody))
                {
                    alternative = new MultipartAlternative();
                    alternative.Add(text);
                    body = alternative;
                }
                else
                {
                    body = text;
                }
            }

            if (!string.IsNullOrEmpty(HtmlBody))
            {
                var        text = new TextPart("html");
                MimeEntity html;

                text.ContentId = MimeUtils.GenerateMessageId();
                text.Text      = HtmlBody;

                if (LinkedResources.Count > 0)
                {
                    var related = new MultipartRelated {
                        Root = text
                    };

                    foreach (var resource in LinkedResources)
                    {
                        related.Add(resource);
                    }

                    html = related;
                }
                else
                {
                    html = text;
                }

                if (alternative != null)
                {
                    alternative.Add(html);
                }
                else
                {
                    body = html;
                }
            }

            if (Attachments.Count > 0)
            {
                var mixed = new Multipart("mixed");

                if (body != null)
                {
                    mixed.Add(body);
                }

                foreach (var attachment in Attachments)
                {
                    mixed.Add(attachment);
                }

                body = mixed;
            }

            return(body ?? new TextPart("plain")
            {
                Text = string.Empty
            });
        }
Example #6
0
        //http://www.mimekit.net/docs/html/T_MimeKit_AttachmentCollection.htm
        //https://www.youtube.com/watch?v=Y2X5wtuzuX4
        //https://www.taithienbo.com/send-email-with-attachments-using-mailkit-for-net-core/
        //https://dotnetcoretutorials.com/2017/11/02/using-mailkit-send-receive-email-asp-net-core/
        public async Task SSendEmailAsync(string fromDisplayName,
                                          string fromEmailAddress,
                                          string toName,
                                          string toEmailAddress,
                                          string subject,
                                          string menssage)
        {
            var email = new MimeMessage();

            email.From.Add(new MailboxAddress(fromDisplayName, fromEmailAddress));
            email.To.Add(new MailboxAddress(toName, toEmailAddress));
            email.Subject = subject;

            var builder = new BodyBuilder();

            // Set the plain-text version of the message text
            builder.TextBody = menssage;

            // In order to reference selfie.jpg from the html text, we'll need to add it
            // to builder.LinkedResources and then use its Content-Id value in the img src.


            var image = builder.LinkedResources.Add(@"C:\transer\imagenes\firmaDigital.PNG");

            image.ContentId = MimeUtils.GenerateMessageId();

            // Set the html version of the message text
            builder.HtmlBody =

                /*string.Format(@"<leftr><img src=""cid:{0}""></left>
                 * <p>El contenido de este mensaje pertenece a TRANSER S.A. y puede ser información privilegiada y confidencial. Si Usted no es el destinatario real del mismo, por favor informe de ello a quien lo envía y destrúyalo en forma inmediata. Está prohibida su retención, grabación, utilización o divulgación con cualquier propósito. Este mensaje ha sido verificado con software antivirus, en consecuencia, TRANSER S.A. no se hace responsable por la presencia en el o en sus anexos de algún virus que pueda generar daños en los equipos o programas del destinatario.<br>
                 * <p>The content of this message belong to TRANSER S.A. and may be privileged and confidential information. If you are not the real recipient, please inform to sender and delete it immediately. The withholding, saving, use or release for any purpose of this message is restricted. This message has been checked with antivirus software; Accordingly, TRANSER S.A. is not liable for the presence of any virus in its attachments that causes or may cause damage to the recipient's equipment or software.<br>
                 * <p>www.transer.com.co<br>", image.ContentId);
                 *
                 *
                 */
                builder.HtmlBody = string.Format(@"<p>El contenido de este mensaje pertenece a TRANSER S.A. y puede ser información privilegiada y confidencial. <br>
                                                           <p>Si Usted no es el destinatario real del mismo, por favor informe de ello a quien lo envía y destrúyalo en <br>
                                                           <p>forma inmediata. Está prohibida su retención, grabación, utilización o divulgación con cualquier propósito.<br>
                                                           <p>Este mensaje ha sido verificado con software antivirus, en consecuencia, TRANSER S.A. no se hace responsable <br>
                                                           <p>por la presencia en el o en sus anexos de algún virus que pueda generar daños en los equipos o programas del <br>
            <p>destinatario.<br>
            <p>www.transer.com.co<br>
            <center><img src=""cid:{0}""></center>", image.ContentId);

            // We may also want to attach a calendar event for Monica's party...


            //builder.Attachments.Add(@"C:\transer\documentos\condorito.pdf");

            // Now we just need to set the message body and we're done
            email.Body = builder.ToMessageBody();


            using (var client = new SmtpClient())
            {
                client.ServerCertificateValidationCallback =
                    (sender, certificate, certChainType, errors) => true;
                client.AuthenticationMechanisms.Remove("XOAUTH2");

                await client.ConnectAsync("smtp.gmail.com", 465, true).ConfigureAwait(false);

                await client.AuthenticateAsync("francisco.montoya.l", "@Jsd2@xr1").ConfigureAwait(false);

                await client.SendAsync(email).ConfigureAwait(false);

                await client.DisconnectAsync(true).ConfigureAwait(false);
            }
        }
Example #7
0
        /// <summary>
        /// Gets the ready made body part for a mail message either
        /// - as TextPart, if there are no inline attachments
        /// - as MultipartRelated with a TextPart and one or more MimeParts of type inline attachments
        /// </summary>
        public override MimeEntity GetBodyPart()
        {
            // remove all Script elements, because they cannot be used in mail messages
            foreach (var element in _htmlDocument.All.Where(e => e is IHtmlScriptElement).ToList())
            {
                element.Remove();
            }

            // set the HTML title tag from email subject
            var titleEle = _htmlDocument.All.FirstOrDefault(m => m is IHtmlTitleElement) as IHtmlTitleElement;

            if (titleEle != null)
            {
                titleEle.Text = _mailMergeMessage.SearchAndReplaceVars(_mailMergeMessage.Subject, _dataItem);
            }

            // read the <base href="..."> tag in order to find the embedded image files later on
            var baseEle = _htmlDocument.All.FirstOrDefault(m => m is IHtmlBaseElement) as IHtmlBaseElement;
            var baseDir = baseEle?.Href == null ? null : new Uri(baseEle.Href);

            // only replace the base url if it was not set programmatically
            if (baseDir != null && _docBaseUri == new Uri(_defaultDocBaseUri))
            {
                _docBaseUri = baseDir;
            }

            // remove if base tag is local file reference, because it's not usable in the resulting HTML
            if (baseEle != null && baseDir != null && baseDir.Scheme == UriScheme.File)
            {
                baseEle.Remove();
            }

            ReplaceImgSrcByCid();

            // replace placeholders only in the HTML Body, because e.g.
            // in the header there may be CSS definitions with curly brace which collide with SmartFormat {placeholders}
            _htmlDocument.Body.InnerHtml = _mailMergeMessage.SearchAndReplaceVars(_htmlDocument.Body.InnerHtml, _dataItem);

            var htmlTextPart = new TextPart("html")
            {
                ContentTransferEncoding = TextTransferEncoding
            };

            htmlTextPart.SetText(CharacterEncoding, DocHtml);  // MimeKit.ContentType.Charset is set using CharacterEncoding
            htmlTextPart.ContentId = MimeUtils.GenerateMessageId();

            if (!InlineAtt.Any())
            {
                return(htmlTextPart);
            }

            /*
             *  multipart/related
             *  text/html
             *  image/jpeg
             *  image/png
             *  image/gif...
             */
            var mpr = new MultipartRelated(htmlTextPart);

            // Produce attachments as part of the multipart/related MIME part,
            // as described in RFC2387
            // Some older clients may need Inline Attachments instead of LinkedResources:
            // RFC2183: 2.1 The Inline Disposition Type
            // A bodypart should be marked `inline' if it is intended to be displayed automatically upon display of the message. Inline
            // bodyparts should be presented in the order in which they occur, subject to the normal semantics of multipart messages.
            foreach (var ia in InlineAtt)
            {
                try
                {
                    var readyInlineAtt = new FileAttachment(_mailMergeMessage.SearchAndReplaceVarsInFilename(ia.Filename, _dataItem), _mailMergeMessage.SearchAndReplaceVars(ia.DisplayName, _dataItem));
                    // create an inline image attachment for the file located at path
                    var attachment = new AttachmentBuilder(readyInlineAtt, CharacterEncoding,
                                                           TextTransferEncoding, BinaryTransferEncoding).GetAttachment();
                    attachment.ContentDisposition = new ContentDisposition(ContentDisposition.Inline);
                    attachment.ContentId          = ia.DisplayName;
                    attachment.FileName           = null; // not needed for inline attachments, save some space

                    mpr.Add(attachment);
                }
                catch (FileNotFoundException)
                {
                    BadInlineFiles.Add(ia.Filename);
                }
                catch (IOException)
                {
                    BadInlineFiles.Add(ia.Filename);
                }
            }
            return(mpr);
        }
Example #8
0
        /// <summary>
        /// Splits the specified message into multiple messages.
        /// </summary>
        /// <remarks>
        /// Splits the specified message into multiple messages, each with a
        /// message/partial body no larger than the max size specified.
        /// </remarks>
        /// <returns>An enumeration of partial messages.</returns>
        /// <param name="message">The message.</param>
        /// <param name="maxSize">The maximum size for each message body.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="message"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// <paramref name="maxSize"/> is less than <c>1</c>.
        /// </exception>
        public static IEnumerable <MimeMessage> Split(MimeMessage message, int maxSize)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (maxSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(maxSize));
            }

            var options = FormatOptions.CloneDefault();

            foreach (HeaderId id in Enum.GetValues(typeof(HeaderId)))
            {
                switch (id)
                {
                case HeaderId.Subject:
                case HeaderId.MessageId:
                case HeaderId.Encrypted:
                case HeaderId.MimeVersion:
                case HeaderId.ContentAlternative:
                case HeaderId.ContentBase:
                case HeaderId.ContentClass:
                case HeaderId.ContentDescription:
                case HeaderId.ContentDisposition:
                case HeaderId.ContentDuration:
                case HeaderId.ContentFeatures:
                case HeaderId.ContentId:
                case HeaderId.ContentIdentifier:
                case HeaderId.ContentLanguage:
                case HeaderId.ContentLength:
                case HeaderId.ContentLocation:
                case HeaderId.ContentMd5:
                case HeaderId.ContentReturn:
                case HeaderId.ContentTransferEncoding:
                case HeaderId.ContentTranslationType:
                case HeaderId.ContentType:
                    break;

                default:
                    options.HiddenHeaders.Add(id);
                    break;
                }
            }

            var memory = new MemoryStream();

            message.WriteTo(options, memory);
            memory.Seek(0, SeekOrigin.Begin);

            if (memory.Length <= maxSize)
            {
                memory.Dispose();

                yield return(message);

                yield break;
            }

            var streams = new List <Stream> ();

#if !NETSTANDARD1_3 && !NETSTANDARD1_6
            var buf = memory.GetBuffer();
#else
            var buf = memory.ToArray();
#endif
            long startIndex = 0;

            while (startIndex < memory.Length)
            {
                // Preferably, we'd split on whole-lines if we can,
                // but if that's not possible, split on max size
                long endIndex = Math.Min(memory.Length, startIndex + maxSize);

                if (endIndex < memory.Length)
                {
                    long ebx = endIndex;

                    while (ebx > (startIndex + 1) && buf[ebx] != (byte)'\n')
                    {
                        ebx--;
                    }

                    if (buf[ebx] == (byte)'\n')
                    {
                        endIndex = ebx + 1;
                    }
                }

                streams.Add(new BoundStream(memory, startIndex, endIndex, true));
                startIndex = endIndex;
            }

            var msgid  = message.MessageId ?? MimeUtils.GenerateMessageId();
            int number = 1;

            foreach (var stream in streams)
            {
                var part = new MessagePartial(msgid, number++, streams.Count)
                {
                    Content = new MimeContent(stream)
                };

                var submessage = CloneMessage(message);
                submessage.MessageId = MimeUtils.GenerateMessageId();
                submessage.Body      = part;

                yield return(submessage);
            }

            yield break;
        }
Example #9
0
        /// <summary>
        /// Parses entity and it's child entities.
        /// </summary>
        internal void Parse(string text)
        {
            StringReader r = new StringReader(text);

            r.ReadToFirstChar();

            // If starts with ( then multipart/xxx, otherwise normal single part entity
            if (r.StartsWith("("))
            {
                // Entities are (entity1)(entity2)(...) <SP> ContentTypeSubType
                while (r.StartsWith("("))
                {
                    IMAP_BODY_Entity entity = new IMAP_BODY_Entity();
                    entity.Parse(r.ReadParenthesized());
                    entity.m_pParentEntity = this;
                    m_pChildEntities.Add(entity);

                    r.ReadToFirstChar();
                }

                // Read multipart values. (nestedMimeEntries) contentTypeSubMediaType
                string contentTypeSubMediaType = r.ReadWord();

                m_pContentType = MimeUtils.ParseMediaType("multipart/" + contentTypeSubMediaType);
            }
            else
            {
                // Basic fields for non-multipart
                // contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine]

                // Content-Type
                string contentTypeMainMediaType = r.ReadWord();
                string contentTypeSubMediaType  = r.ReadWord();
                if (contentTypeMainMediaType.ToUpper() != "NIL" && contentTypeSubMediaType.ToUpper() != "NIL")
                {
                    m_pContentType =
                        MimeUtils.ParseMediaType(contentTypeMainMediaType + "/" + contentTypeSubMediaType);
                }

                // Content-Type header field parameters
                // Parameters syntax: "name" <SP> "value" <SP> "name" <SP> "value" <SP> ... .
                r.ReadToFirstChar();
                string conentTypeParameters = "NIL";
                if (r.StartsWith("("))
                {
                    conentTypeParameters = r.ReadParenthesized();

                    StringReader contentTypeParamReader =
                        new StringReader(MimeUtils.DecodeWords(conentTypeParameters));
                    List <HeaderFieldParameter> parameters = new List <HeaderFieldParameter>();
                    while (contentTypeParamReader.Available > 0)
                    {
                        string parameterName  = contentTypeParamReader.ReadWord();
                        string parameterValue = contentTypeParamReader.ReadWord();

                        parameters.Add(new HeaderFieldParameter(parameterName, parameterValue));
                    }
                    m_pContentTypeParams = parameters.ToArray();
                }
                else
                {
                    // Skip NIL
                    r.ReadWord();
                }

                // Content-ID:
                string contentID = r.ReadWord();
                if (contentID.ToUpper() != "NIL")
                {
                    m_ContentID = contentID;
                }

                // Content-Description:
                string contentDescription = r.ReadWord();
                if (contentDescription.ToUpper() != "NIL")
                {
                    m_ContentDescription = contentDescription;
                }

                // Content-Transfer-Encoding:
                string contentEncoding = r.ReadWord();
                if (contentEncoding.ToUpper() != "NIL")
                {
                    m_ContentEncoding = MimeUtils.ParseContentTransferEncoding(contentEncoding);
                }

                // Content Encoded data size in bytes
                string contentSize = r.ReadWord();
                if (contentSize.ToUpper() != "NIL")
                {
                    m_ContentSize = Convert.ToInt32(contentSize);
                }

                // Only for ContentType message/rfc822
                if (ContentType == MediaType_enum.Message_rfc822)
                {
                    r.ReadToFirstChar();

                    // envelope
                    if (r.StartsWith("("))
                    {
                        m_pEnvelope = new IMAP_Envelope();
                        m_pEnvelope.Parse(r.ReadParenthesized());
                    }
                    else
                    {
                        // Skip NIL, ENVELOPE wasn't included
                        r.ReadWord();
                    }

                    // TODO:
                    // BODYSTRUCTURE

                    // contentLine
                }

                // Only for ContentType text/xxx
                if (contentTypeMainMediaType.ToLower() == "text")
                {
                    // contentLine
                    string contentLines = r.ReadWord();
                    if (contentLines.ToUpper() != "NIL")
                    {
                        m_ContentLines = Convert.ToInt32(contentLines);
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Construct secified mime entity ENVELOPE string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <returns></returns>
        public static string ConstructEnvelope(MimeEntity entity)
        {
            /* RFC 3501 7.4.2
             *                  ENVELOPE
             *                          A parenthesized list that describes the envelope structure of a
             *                          message.  This is computed by the server by parsing the
             *                          [RFC-2822] header into the component parts, defaulting various
             *                          fields as necessary.
             *
             *                          The fields of the envelope structure are in the following
             *                          order: date, subject, from, sender, reply-to, to, cc, bcc,
             *                          in-reply-to, and message-id.  The date, subject, in-reply-to,
             *                          and message-id fields are strings.  The from, sender, reply-to,
             *                          to, cc, and bcc fields are parenthesized lists of address
             *                          structures.
             *
             *                          An address structure is a parenthesized list that describes an
             *                          electronic mail address.  The fields of an address structure
             *                          are in the following order: personal name, [SMTP]
             *                          at-domain-list (source route), mailbox name, and host name.
             *
             *                          [RFC-2822] group syntax is indicated by a special form of
             *                          address structure in which the host name field is NIL.  If the
             *                          mailbox name field is also NIL, this is an end of group marker
             *                          (semi-colon in RFC 822 syntax).  If the mailbox name field is
             *                          non-NIL, this is a start of group marker, and the mailbox name
             *                          field holds the group name phrase.
             *
             *                          If the Date, Subject, In-Reply-To, and Message-ID header lines
             *                          are absent in the [RFC-2822] header, the corresponding member
             *                          of the envelope is NIL; if these header lines are present but
             *                          empty the corresponding member of the envelope is the empty
             *                          string.
             *
             *                                  Note: some servers may return a NIL envelope member in the
             *                                  "present but empty" case.  Clients SHOULD treat NIL and
             *                                  empty string as identical.
             *
             *                                  Note: [RFC-2822] requires that all messages have a valid
             *                                  Date header.  Therefore, the date member in the envelope can
             *                                  not be NIL or the empty string.
             *
             *                                  Note: [RFC-2822] requires that the In-Reply-To and
             *                                  Message-ID headers, if present, have non-empty content.
             *                                  Therefore, the in-reply-to and message-id members in the
             *                                  envelope can not be the empty string.
             *
             *                          If the From, To, cc, and bcc header lines are absent in the
             *                          [RFC-2822] header, or are present but empty, the corresponding
             *                          member of the envelope is NIL.
             *
             *                          If the Sender or Reply-To lines are absent in the [RFC-2822]
             *                          header, or are present but empty, the server sets the
             *                          corresponding member of the envelope to be the same value as
             *                          the from member (the client is not expected to know to do
             *                          this).
             *
             *                                  Note: [RFC-2822] requires that all messages have a valid
             *                                  From header.  Therefore, the from, sender, and reply-to
             *                                  members in the envelope can not be NIL.
             *
             *                          ENVELOPE ("date" "subject" from sender reply-to to cc bcc "in-reply-to" "messageID")
             */

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();

            retVal.Append("(");

            // date
            if (entity.Header.Contains("Date:"))
            {
                retVal.Append(TextUtils.QuoteString(MimeUtils.DateTimeToRfc2822(entity.Date)));
            }
            else
            {
                retVal.Append("NIL");
            }

            // subject
            if (entity.Subject != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.Subject)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // from
            if (entity.From != null && entity.From.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // sender
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            if (entity.Sender != null)
            {
                retVal.Append(" (");

                retVal.Append(ConstructAddress(entity.Sender));

                retVal.Append(")");
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // reply-to
            if (entity.ReplyTo != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.ReplyTo));
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // to
            if (entity.To != null && entity.To.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.To));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // cc
            if (entity.Cc != null && entity.Cc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Cc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // bcc
            if (entity.Bcc != null && entity.Bcc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Bcc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // in-reply-to
            if (entity.InReplyTo != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.InReplyTo)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // message-id
            if (entity.MessageID != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.MessageID)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            retVal.Append(")");

            return(retVal.ToString());
        }
Example #11
0
        /// <summary>
        /// Parses ENVELOPE from IMAP envelope string.
        /// </summary>
        /// <param name="envelopeString">Envelope string.</param>
        public void Parse(string envelopeString)
        {
            if (envelopeString.StartsWith("("))
            {
                envelopeString = envelopeString.Substring(1);
            }
            if (envelopeString.EndsWith(")"))
            {
                envelopeString = envelopeString.Substring(0, envelopeString.Length - 1);
            }

            string       word = "";
            StringReader r    = new StringReader(envelopeString);

            #region Date

            // Date
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_Date = DateTime.MinValue;
            }
            else
            {
                try
                {
                    m_Date = MimeUtils.ParseDate(word);
                }
                catch
                {
                    // Failed to parse date, return minimum.
                    m_Date = DateTime.MinValue;
                }
            }

            #endregion

            #region Subject

            // Subject
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_Subject = null;
            }
            else
            {
                m_Subject = MIME_Encoding_EncodedWord.DecodeS(word);
            }

            #endregion

            #region From

            // From
            m_From = ParseAddresses(r);

            #endregion

            #region Sender

            // Sender
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            MailboxAddress[] sender = ParseAddresses(r);
            if (sender != null && sender.Length > 0)
            {
                m_Sender = sender[0];
            }
            else
            {
                m_Sender = null;
            }

            #endregion

            #region ReplyTo

            // ReplyTo
            m_ReplyTo = ParseAddresses(r);

            #endregion

            #region To

            // To
            m_To = ParseAddresses(r);

            #endregion

            #region Cc

            // Cc
            m_Cc = ParseAddresses(r);

            #endregion

            #region Bcc

            // Bcc
            m_Bcc = ParseAddresses(r);

            #endregion

            #region InReplyTo

            // InReplyTo
            r.ReadToFirstChar();
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_InReplyTo = null;
            }
            else
            {
                m_InReplyTo = word;
            }

            #endregion

            #region MessageID

            // MessageID
            r.ReadToFirstChar();
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_MessageID = null;
            }
            else
            {
                m_MessageID = word;
            }

            #endregion
        }
Example #12
0
        public void ExampleContextBuild()
        {
            //
            // Context
            //
            var contextBuilder = new ContextBuilder();

            contextBuilder
            .WithContentId(MimeUtils.GenerateMessageId())
            .WithDisposition("metadata.txt")
            .WithTransferEncoding(ContentEncoding.Base64)
            .WithVersion("1.0")
            .WithId(MimeUtils.GenerateMessageId())
            .WithPatientId(
                new PatientInstance
            {
                PidContext     = "2.16.840.1.113883.19.999999",
                LocalPatientId = "123456"
            }.ToList()
                )
            .WithType(ContextStandard.Type.CategoryRadiology, ContextStandard.Type.ActionReport)
            .WithPurpose(ContextStandard.Purpose.PurposeResearch)
            .WithPatient(
                new Patient
            {
                GivenName           = "John",
                SurName             = "Doe",
                MiddleName          = "Jacob",
                DateOfBirth         = "1961-12-31",
                Gender              = "M",
                PostalCode          = "12345",
                StateOrProvinceName = "New York",
                LocalityName        = "John County",
                Country             = "US",
                DirectAddress       = "*****@*****.**"
            }
                );

            var context = contextBuilder.Build();

            //
            // Mime message and simple body
            //
            var message = new MimeMessage();

            message.From.Add(new MailboxAddress("HoboJoe", "*****@*****.**"));
            message.To.Add(new MailboxAddress("Toby", "*****@*****.**"));
            message.Subject = "Sample message with pdf and context attached";
            message.Headers.Add(MailStandard.Headers.DirectContext, context.Headers[ContextStandard.ContentIdHeader]);
            Assert.StartsWith("<", context.Headers[HeaderId.ContentId]);
            Assert.EndsWith(">", context.Headers[HeaderId.ContentId]);

            var body = new TextPart("plain")
            {
                Text = @"Simple Body"
            };

            //
            // Mime message and simple body
            //
            var pdf = new MimePart("application/pdf")
            {
                ContentDisposition      = new ContentDisposition(ContentDisposition.Attachment),
                FileName                = "report.pdf",
                ContentTransferEncoding = ContentEncoding.Base64
            };

            var byteArray = Encoding.UTF8.GetBytes("Fake PDF (invalid)");
            var stream    = new MemoryStream(byteArray);

            pdf.Content = new MimeContent(stream);

            //
            // Multi part construction
            //
            var multiPart = new Multipart("mixed")
            {
                body,
                contextBuilder.BuildMimePart(),
                pdf
            };

            message.Body = multiPart;


            //
            // Assert context can be serialized and parsed.
            //
            var messageParsed = MimeMessage.Load(message.ToString().ToStream());

            Assert.True(messageParsed.ContainsDirectContext());
            Assert.Equal(context.ContentId, messageParsed.DirectContextId());
            Assert.StartsWith("<", messageParsed.Headers[MailStandard.Headers.DirectContext]);
            Assert.EndsWith(">", messageParsed.Headers[MailStandard.Headers.DirectContext]);

            var contextParsed = message.DirectContext();

            Assert.NotNull(contextParsed);

            //
            // Headers
            //
            Assert.Equal("text", contextParsed.ContentType.MediaType);
            Assert.Equal("plain", contextParsed.ContentType.MediaSubtype);
            Assert.Equal("attachment", contextParsed.ContentDisposition.Disposition);
            Assert.Equal("metadata.txt", contextParsed.ContentDisposition.FileName);
            Assert.Equal(context.ContentId, contextParsed.ContentId);

            //
            // Metadata
            //
            Assert.Equal("1.0", contextParsed.Metadata.Version);
            Assert.Equal(context.Metadata.Id, contextParsed.Metadata.Id);

            //
            // Metatdata PatientId
            //
            Assert.Equal("2.16.840.1.113883.19.999999:123456", contextParsed.Metadata.PatientId);
            Assert.Single(contextParsed.Metadata.PatientIdentifier);
            var patientIdentifiers = Enumerable.ToList(contextParsed.Metadata.PatientIdentifier);

            Assert.Equal("2.16.840.1.113883.19.999999", patientIdentifiers[0].PidContext);
            Assert.Equal("123456", patientIdentifiers[0].LocalPatientId);

            //
            // Metatdata Type
            //
            Assert.Equal("radiology/report", contextParsed.Metadata.Type.ToString());
            Assert.Equal("radiology", contextParsed.Metadata.Type.Category);
            Assert.Equal("report", contextParsed.Metadata.Type.Action);

            //
            // Metatdata Purpose
            //
            Assert.Equal("research", contextParsed.Metadata.Purpose);

            //
            // Metadata Patient
            //
            Assert.Equal("givenName=John; surname=Doe; middleName=Jacob; dateOfBirth=1961-12-31; gender=M; localityName=John County; stateOrProvinceName=New York; postalCode=12345; country=US; [email protected]",
                         contextParsed.Metadata.Patient.ToString());

            Assert.Equal("John", contextParsed.Metadata.Patient.GivenName);
            Assert.Equal("Doe", contextParsed.Metadata.Patient.SurName);
            Assert.Equal("1961-12-31", contextParsed.Metadata.Patient.DateOfBirth);
            Assert.Equal("*****@*****.**", context.Metadata.Patient.DirectAddress);
            Assert.Equal("John County", context.Metadata.Patient.LocalityName);
            Assert.Equal("US", context.Metadata.Patient.Country);
            Assert.Equal("New York", context.Metadata.Patient.StateOrProvinceName);
        }
Example #13
0
 private void button2_Click(object sender, EventArgs evnt) //gönderme işlemi
 {
     if (textBox1.Text != "" && textBox2.Text != "")
     {
         metinbaslangicIndex = 0;
         SmtpClient  client  = new SmtpClient();
         MimeMessage message = new MimeMessage();
         BodyBuilder builder = new BodyBuilder();
         client.ServerCertificateValidationCallback = (s, c, h, e) => true;
         client.Connect("smtp.gmail.com", 465, SecureSocketOptions.SslOnConnect);
         client.Authenticate(login_user.Instance.Eposta, login_user.Instance.sifre);
         bool hata_varmı = false;
         bool loop       = true;
         rtf = richTextBox1.Rtf;
         while (loop)
         {
             try
             {
                 tut = ExtractImgRtf(rtf);
             }
             catch (Exception)
             {
                 hata_varmı = true;
             }
             try
             {
                 bool             duplicate_engelleme = false;
                 IMarkupConverter markupConverter     = new MarkupConverter.MarkupConverter();
                 if (hata_varmı == false)
                 {
                     for (int i = 0; i < bfile.Count; i++)
                     {
                         if (bfile[i].bodyfile_string == tut && duplicate_engelleme == false)
                         {
                             duplicate_engelleme = true;
                             string body = rtf.Substring(metinbaslangicIndex, startIndex - metinbaslangicIndex);
                             metinbaslangicIndex = (endIndex + 12);
                             var bodyfile = builder.LinkedResources.Add(bfile[i].file_name, bfile[i].bodyfile_byte);
                             bodyfile.ContentId = MimeUtils.GenerateMessageId();
                             //try catch gelcek ve text html yerine textx döncek if error
                             string html_body = markupConverter.ConvertRtfToHtml(body);
                             builder.HtmlBody += html_body;
                             builder.HtmlBody += string.Format(@"<img src=""cid:{0}"" width={1} height={2} > ", bodyfile.ContentId, width, height);
                         }
                     }
                     duplicate_engelleme = false;
                 }
                 else
                 {
                     string body      = rtf.Substring(metinbaslangicIndex, richTextBox1.Rtf.Length - metinbaslangicIndex);
                     string html_body = markupConverter.ConvertRtfToHtml(body);
                     builder.HtmlBody += html_body;
                     loop              = false;
                 }
             }
             catch (Exception ht)
             {
                 MessageBox.Show("Hata: " + ht);
                 string body = richTextBox1.Text;
                 builder.TextBody = body;
                 loop             = false;
             }
         }
         bool empty = !attachment_dondur.Any();
         if (empty != true)
         {
             foreach (string yol in attachment_dondur)
             {
                 builder.Attachments.Add(@"" + yol);
             }
         }
         bool mesaj_gittimi = true;
         try
         {
             message.From.Add(MailboxAddress.Parse(login_user.Instance.Eposta));
             message.To.Add(MailboxAddress.Parse(textBox1.Text));
             message.Subject = textBox2.Text;
             message.Body    = builder.ToMessageBody();
             client.Send(message);
         }
         catch (Exception ht)
         {
             MessageBox.Show("Mail yollanırken hata ile karşılaşıldı: " + ht);
             mesaj_gittimi = false;
         }
         finally
         {
             startIndex          = 0;
             endIndex            = 0;
             metinbaslangicIndex = 0;
             bfile.Clear();
             richTextBox1.Clear();
         }
         if (mesaj_gittimi == true)
         {
             MessageBox.Show("Mesaj Gönderildi.");
         }
     }
     else
     {
         if (textBox1.Text == "")
         {
             textBox1.Text = "Gönderilecek kişi ksmı boş geçilemez.";
         }
         if (textBox2.Text == "")
         {
             textBox2.Text = "Konu ksmı boş geçilemez.";
         }
         MessageBox.Show("Lütfen Her bir bölümü doldurduğunuza emin olunuz...");
     }
 }
Example #14
0
 static void EncodeGroup(StringBuilder builder, GroupAddress group)
 {
     builder.AppendFormat("(NIL NIL {0} NIL)", MimeUtils.Quote(group.Name));
     EncodeInternetAddressListAddresses(builder, group.Members);
     builder.Append("(NIL NIL NIL NIL)");
 }
Example #15
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ContentDisposition disposition)
        {
            string type;
            int    atom;

            disposition = null;

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            if (index >= endIndex)
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format("Expected atom token at position {0}", index), index, index);
                }

                return(false);
            }

            atom = index;
            if (text[index] == '"')
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format("Unxpected qstring token at position {0}", atom), atom, index);
                }

                // Note: This is a work-around for broken mailers that quote the disposition value...
                //
                // See https://github.com/jstedfast/MailKit/issues/486 for details.
                if (!ParseUtils.SkipQuoted(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                type = CharsetUtils.ConvertToUnicode(options, text, atom, index - atom);
                type = MimeUtils.Unquote(type);

                if (string.IsNullOrEmpty(type))
                {
                    type = Attachment;
                }
            }
            else
            {
                if (!ParseUtils.SkipAtom(text, ref index, endIndex))
                {
                    if (throwOnError)
                    {
                        throw new ParseException(string.Format("Invalid atom token at position {0}", atom), atom, index);
                    }

                    // Note: this is a work-around for broken mailers that do not specify a disposition value...
                    //
                    // See https://github.com/jstedfast/MailKit/issues/486 for details.
                    if (index > atom || text[index] != (byte)';')
                    {
                        return(false);
                    }

                    type = Attachment;
                }
                else
                {
                    type = Encoding.ASCII.GetString(text, atom, index - atom);
                }
            }

            disposition             = new ContentDisposition();
            disposition.disposition = type;

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            if (index >= endIndex)
            {
                return(true);
            }

            if (text[index] != (byte)';')
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format("Expected ';' at position {0}", index), index, index);
                }

                return(false);
            }

            index++;

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            if (index >= endIndex)
            {
                return(true);
            }

            ParameterList parameters;

            if (!ParameterList.TryParse(options, text, ref index, endIndex, throwOnError, out parameters))
            {
                return(false);
            }

            disposition.Parameters = parameters;

            return(true);
        }
        /// <summary>
        /// Constructs specified entity and it's childentities bodystructure string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <param name="bodystructure">Specifies if to construct BODY or BODYSTRUCTURE.</param>
        /// <returns></returns>
        private static string ConstructParts(MimeEntity entity, bool bodystructure)
        {
            /* RFC 3501 7.4.2 BODYSTRUCTURE
             *                                            BODY A form of BODYSTRUCTURE without extension data.
             *
             *                  A parenthesized list that describes the [MIME-IMB] body
             *                  structure of a message.  This is computed by the server by
             *                  parsing the [MIME-IMB] header fields, defaulting various fields
             *                  as necessary.
             *
             *                  For example, a simple text message of 48 lines and 2279 octets
             *                  can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
             *                  "US-ASCII") NIL NIL "7BIT" 2279 48)
             *
             *                  Multiple parts are indicated by parenthesis nesting.  Instead
             *                  of a body type as the first element of the parenthesized list,
             *                  there is a sequence of one or more nested body structures.  The
             *                  second element of the parenthesized list is the multipart
             *                  subtype (mixed, digest, parallel, alternative, etc.).
             *
             *                  For example, a two part message consisting of a text and a
             *                  BASE64-encoded text attachment can have a body structure of:
             *                  (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
             *                  23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
             *                  "<*****@*****.**>" "Compiler diff"
             *                  "BASE64" 4554 73) "MIXED")
             *
             *                  Extension data follows the multipart subtype.  Extension data
             *                  is never returned with the BODY fetch, but can be returned with
             *                  a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
             *                  the defined order.  The extension data of a multipart body part
             *                  are in the following order:
             *
             *                  body parameter parenthesized list
             *                          A parenthesized list of attribute/value pairs [e.g., ("foo"
             *                          "bar" "baz" "rag") where "bar" is the value of "foo", and
             *                          "rag" is the value of "baz"] as defined in [MIME-IMB].
             *
             *                  body disposition
             *                          A parenthesized list, consisting of a disposition type
             *                          string, followed by a parenthesized list of disposition
             *                          attribute/value pairs as defined in [DISPOSITION].
             *
             *                  body language
             *                          A string or parenthesized list giving the body language
             *                          value as defined in [LANGUAGE-TAGS].
             *
             *                  body location
             *                          A string list giving the body content URI as defined in [LOCATION].
             *
             *                  Any following extension data are not yet defined in this
             *                  version of the protocol.  Such extension data can consist of
             *                  zero or more NILs, strings, numbers, or potentially nested
             *                  parenthesized lists of such data.  Client implementations that
             *                  do a BODYSTRUCTURE fetch MUST be prepared to accept such
             *                  extension data.  Server implementations MUST NOT send such
             *                  extension data until it has been defined by a revision of this
             *                  protocol.
             *
             *                  The basic fields of a non-multipart body part are in the
             *                  following order:
             *
             *                  body type
             *                          A string giving the content media type name as defined in [MIME-IMB].
             *
             *                  body subtype
             *                           A string giving the content subtype name as defined in [MIME-IMB].
             *
             *                  body parameter parenthesized list
             *                          A parenthesized list of attribute/value pairs [e.g., ("foo"
             *                          "bar" "baz" "rag") where "bar" is the value of "foo" and
             *                          "rag" is the value of "baz"] as defined in [MIME-IMB].
             *
             *                  body id
             *                          A string giving the content id as defined in [MIME-IMB].
             *
             *                  body description
             *                          A string giving the content description as defined in [MIME-IMB].
             *
             *                  body encoding
             *                          A string giving the content transfer encoding as defined in	[MIME-IMB].
             *
             *                  body size
             *                          A number giving the size of the body in octets.  Note that
             *                          this size is the size in its transfer encoding and not the
             *                          resulting size after any decoding.
             *
             *                  A body type of type MESSAGE and subtype RFC822 contains,
             *                  immediately after the basic fields, the envelope structure,
             *                  body structure, and size in text lines of the encapsulated
             *                  message.
             *
             *                  A body type of type TEXT contains, immediately after the basic
             *                  fields, the size of the body in text lines.  Note that this
             *                  size is the size in its content transfer encoding and not the
             *                  resulting size after any decoding.
             *
             *                  Extension data follows the basic fields and the type-specific
             *                  fields listed above.  Extension data is never returned with the
             *                  BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
             *                  Extension data, if present, MUST be in the defined order.
             *
             *                  The extension data of a non-multipart body part are in the
             *                  following order:
             *
             *                  body MD5
             *                          A string giving the body MD5 value as defined in [MD5].
             *
             *                  body disposition
             *                          A parenthesized list with the same content and function as
             *                          the body disposition for a multipart body part.
             *
             *                  body language
             *                          A string or parenthesized list giving the body language
             *                          value as defined in [LANGUAGE-TAGS].
             *
             *                  body location
             *                          A string list giving the body content URI as defined in [LOCATION].
             *
             *                  Any following extension data are not yet defined in this
             *                  version of the protocol, and would be as described above under
             *                  multipart extension data.
             *
             *
             *                  // We don't construct extention fields like rfc says:
             *                          Server implementations MUST NOT send such
             *                          extension data until it has been defined by a revision of this
             *                          protocol.
             *
             *
             *                  contentTypeMainMediaType - Example: 'TEXT'
             *                  contentTypeSubMediaType  - Example: 'PLAIN'
             *                  conentTypeParameters     - Example: '("CHARSET" "iso-8859-1" ...)'
             *                  contentID                - Content-ID: header field value.
             *                  contentDescription       - Content-Description: header field value.
             *                  contentEncoding          - Content-Transfer-Encoding: header field value.
             *                  contentSize              - mimeEntity ENCODED data size
             *                  [envelope]               - NOTE: included only if contentType = "message" !!!
             *                  [contentLines]           - number of ENCODED data lines. NOTE: included only if contentType = "text" !!!
             *
             *                  // Basic fields for multipart
             *                  (nestedMimeEntries) contentTypeSubMediaType
             *
             *                  // Basic fields for non-multipart
             *                  contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine]
             *
             */

            StringBuilder retVal = new StringBuilder();

            // Multipart message
            if ((entity.ContentType & MediaType_enum.Multipart) != 0)
            {
                retVal.Append("(");

                // Construct child entities.
                foreach (MimeEntity childEntity in entity.ChildEntities)
                {
                    // Construct child entity. This can be multipart or non multipart.
                    retVal.Append(ConstructParts(childEntity, bodystructure));
                }

                // Add contentTypeSubMediaType
                string contentType = entity.ContentTypeString.Split(';')[0];
                if (contentType.Split('/').Length == 2)
                {
                    retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                retVal.Append(")");
            }
            // Single part message
            else
            {
                retVal.Append("(");

                // NOTE: all header fields and parameters must in ENCODED form !!!

                // Add contentTypeMainMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append("\"" + entity.ContentTypeString.Split('/')[0] + "\"");
                    }
                    else
                    {
                        retVal.Append("NIL");
                    }
                }
                else
                {
                    retVal.Append("NIL");
                }

                // contentTypeSubMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // conentTypeParameters - Syntax: {("name" SP "value" *(SP "name" SP "value"))}
                if (entity.ContentTypeString != null)
                {
                    ParametizedHeaderField contentTypeParameters =
                        new ParametizedHeaderField(entity.Header.GetFirst("Content-Type:"));
                    if (contentTypeParameters.Parameters.Count > 0)
                    {
                        retVal.Append(" (");

                        bool first = true;
                        foreach (HeaderFieldParameter param in contentTypeParameters.Parameters)
                        {
                            // For first item, don't add SP
                            if (!first)
                            {
                                retVal.Append(" ");
                            }
                            else
                            {
                                // Clear first flag
                                first = false;
                            }

                            retVal.Append("\"" + param.Name + "\" \"" +
                                          MimeUtils.EncodeHeaderField(param.Value) + "\"");
                        }

                        retVal.Append(")");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentID
                string contentID = entity.ContentID;
                if (contentID != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentID) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentDescription
                string contentDescription = entity.ContentDescription;
                if (contentDescription != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentDescription) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentEncoding
                HeaderField contentEncoding = entity.Header.GetFirst("Content-Transfer-Encoding:");
                if (contentEncoding != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentEncoding.Value) + "\"");
                }
                else
                {
                    // If not specified, then must be 7bit.
                    retVal.Append(" \"7bit\"");
                }

                // contentSize
                if (entity.DataEncoded != null)
                {
                    retVal.Append(" " + entity.DataEncoded.Length);
                }
                else
                {
                    retVal.Append(" 0");
                }

                // envelope ---> FOR ContentType: message/rfc822 ONLY ###
                if ((entity.ContentType & MediaType_enum.Message_rfc822) != 0)
                {
                    retVal.Append(" " + IMAP_Envelope.ConstructEnvelope(entity));

                    // TODO: BODYSTRUCTURE,LINES
                }

                // contentLines ---> FOR ContentType: text/xxx ONLY ###
                if ((entity.ContentType & MediaType_enum.Text) != 0)
                {
                    if (entity.DataEncoded != null)
                    {
                        long             lineCount = 0;
                        StreamLineReader r         = new StreamLineReader(new MemoryStream(entity.DataEncoded));
                        byte[]           line      = r.ReadLine();
                        while (line != null)
                        {
                            lineCount++;

                            line = r.ReadLine();
                        }

                        retVal.Append(" " + lineCount);
                    }
                    else
                    {
                        retVal.Append(" 0");
                    }
                }

                retVal.Append(")");
            }

            return(retVal.ToString());
        }
Example #17
0
        /// <summary>
        /// This will load up the Email template and generate the HTML
        /// </summary>
        /// <param name="model"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public async Task SendAdHoc(NotificationMessage model, EmailNotificationSettings settings)
        {
            try
            {
                var email = new EmailBasicTemplate();

                var customization = await CustomizationSettings.GetSettingsAsync();

                var html = email.LoadTemplate(model.Subject, model.Message, null, customization.Logo);

                var messageId = MimeUtils.GenerateMessageId();
                if (customization.ApplicationUrl.HasValue())
                {
                    if (Uri.TryCreate(customization.ApplicationUrl, UriKind.RelativeOrAbsolute, out var url))
                    {
                        messageId = MimeUtils.GenerateMessageId(url.IdnHost);
                    }
                }

                var textBody = string.Empty;

                model.Other.TryGetValue("PlainTextBody", out textBody);
                var body = new BodyBuilder
                {
                    HtmlBody = html,
                    TextBody = textBody
                };

                var message = new MimeMessage
                {
                    Body      = body.ToMessageBody(),
                    Subject   = model.Subject,
                    MessageId = messageId
                };
                message.From.Add(new MailboxAddress(string.IsNullOrEmpty(settings.SenderName) ? settings.SenderAddress : settings.SenderName, settings.SenderAddress));
                if (model.To.HasValue())
                {
                    message.To.Add(new MailboxAddress(model.To, model.To));
                }

                // Check for BCC
                if (model.Other.TryGetValue("bcc", out var bcc))
                {
                    var bccList = bcc.Split(',', StringSplitOptions.RemoveEmptyEntries);
                    foreach (var item in bccList)
                    {
                        message.Bcc.Add(new MailboxAddress(item, item));
                    }
                }

                using (var client = new SmtpClient())
                {
                    if (settings.DisableCertificateChecking)
                    {
                        // Disable validation of the certificate associated with the SMTP service
                        // Helpful when the TLS certificate is not in the certificate store of the server
                        // Does carry the risk of man in the middle snooping
                        client.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
                    }

                    if (settings.DisableTLS)
                    {
                        // Does not attempt to use either TLS or SSL
                        // Helpful when MailKit finds a TLS certificate, but it unable to use it
                        client.Connect(settings.Host, settings.Port, MailKit.Security.SecureSocketOptions.None);
                    }
                    else
                    {
                        client.Connect(settings.Host, settings.Port); // Let MailKit figure out the correct SecureSocketOptions.
                    }

                    // Note: since we don't have an OAuth2 token, disable
                    // the XOAUTH2 authentication mechanism.
                    client.AuthenticationMechanisms.Remove("XOAUTH2");

                    if (settings.Authentication)
                    {
                        client.Authenticate(settings.Username, settings.Password);
                    }
                    _log.LogDebug("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
                    await client.SendAsync(message);

                    await client.DisconnectAsync(true);
                }
            }
            catch (Exception e)
            {
                _log.LogError(e, "Exception when attempting to send an email");
                throw;
            }
        }
Example #18
0
        static IDictionary <string, ThreadableNode> CreateIdTable(IEnumerable <IMessageSummary> messages)
        {
            var            ids = new Dictionary <string, ThreadableNode> (StringComparer.OrdinalIgnoreCase);
            ThreadableNode node;

            foreach (var message in messages)
            {
                if (message.Envelope == null)
                {
                    throw new ArgumentException("One or more messages is missing information needed for threading.", nameof(messages));
                }

                var id = message.Envelope.MessageId;

                if (string.IsNullOrEmpty(id))
                {
                    id = MimeUtils.GenerateMessageId();
                }

                if (ids.TryGetValue(id, out node))
                {
                    if (node.Message == null)
                    {
                        // a previously processed message referenced this message
                        node.Message = message;
                    }
                    else
                    {
                        // a duplicate message-id, just create a dummy id and use that
                        id   = MimeUtils.GenerateMessageId();
                        node = null;
                    }
                }

                if (node == null)
                {
                    // create a new ThreadContainer for this message and add it to ids
                    node = new ThreadableNode(message);
                    ids.Add(id, node);
                }

                ThreadableNode parent = null;
                foreach (var reference in message.References)
                {
                    ThreadableNode referenced;

                    if (!ids.TryGetValue(reference, out referenced))
                    {
                        // create a dummy container for the referenced message
                        referenced = new ThreadableNode(null);
                        ids.Add(reference, referenced);
                    }

                    // chain up the references, disallowing loops
                    if (parent != null && referenced.Parent == null && parent != referenced && !parent.Children.Contains(referenced))
                    {
                        parent.Children.Add(referenced);
                        referenced.Parent = parent;
                    }

                    parent = referenced;
                }

                // don't allow loops
                if (parent != null && (parent == node || node.Children.Contains(parent)))
                {
                    parent = null;
                }

                if (node.HasParent)
                {
                    // unlink from our old parent
                    node.Parent.Children.Remove(node);
                    node.Parent = null;
                }

                if (parent != null)
                {
                    // add it as a child of our new parent
                    parent.Children.Add(node);
                    node.Parent = parent;
                }
            }

            return(ids);
        }
Example #19
0
        EncodeMethod GetEncodeMethod(FormatOptions options, string name, string value, out string quoted)
        {
            var          method = EncodeMethod.None;
            EncodeMethod encode;

            switch (encodingMethod)
            {
            default:
                if (options.ParameterEncodingMethod == ParameterEncodingMethod.Rfc2231)
                {
                    encode = EncodeMethod.Rfc2231;
                }
                else
                {
                    encode = EncodeMethod.Rfc2047;
                }
                break;

            case ParameterEncodingMethod.Rfc2231:
                encode = EncodeMethod.Rfc2231;
                break;

            case ParameterEncodingMethod.Rfc2047:
                encode = EncodeMethod.Rfc2047;
                break;
            }

            quoted = null;

            if (name.Length + 1 + value.Length >= options.MaxLineLength)
            {
                return(encode);
            }

            for (int i = 0; i < value.Length; i++)
            {
                if (value[i] < 128)
                {
                    var c = (byte)value[i];

                    if (c.IsCtrl())
                    {
                        return(encode);
                    }

                    if (!c.IsAttr())
                    {
                        method = EncodeMethod.Quote;
                    }
                }
                else if (options.International)
                {
                    method = EncodeMethod.Quote;
                }
                else
                {
                    return(encode);
                }
            }

            if (method == EncodeMethod.Quote)
            {
                quoted = MimeUtils.Quote(value);

                if (name.Length + 1 + quoted.Length >= options.MaxLineLength)
                {
                    return(encode);
                }
            }

            return(method);
        }
Example #20
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ParameterList paramList)
        {
            var rfc2231 = new Dictionary <string, List <NameValuePair> > (MimeUtils.OrdinalIgnoreCase);
            var @params = new List <NameValuePair> ();
            List <NameValuePair> parts;

            paramList = null;

            do
            {
                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (index >= endIndex)
                {
                    break;
                }

                // handle empty parameter name/value pairs
                if (text[index] == (byte)';')
                {
                    index++;
                    continue;
                }

                NameValuePair pair;
                if (!TryParseNameValuePair(options, text, ref index, endIndex, throwOnError, out pair))
                {
                    return(false);
                }

                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (pair.Id.HasValue)
                {
                    if (rfc2231.TryGetValue(pair.Name, out parts))
                    {
                        parts.Add(pair);
                    }
                    else
                    {
                        parts = new List <NameValuePair> ();
                        rfc2231[pair.Name] = parts;
                        @params.Add(pair);
                        parts.Add(pair);
                    }
                }
                else
                {
                    @params.Add(pair);
                }

                if (index >= endIndex)
                {
                    break;
                }

                if (text[index] != (byte)';')
                {
                    if (options.ParameterComplianceMode == RfcComplianceMode.Strict)
                    {
                        if (throwOnError)
                        {
                            throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Invalid parameter list token at offset {0}", index), index, index);
                        }

                        return(false);
                    }
                }
                else
                {
                    // Skip over ';'
                    index++;
                }
            } while (true);

            paramList = new ParameterList();
            var hex = new HexDecoder();

            foreach (var param in @params)
            {
                var       method     = ParameterEncodingMethod.Default;
                int       startIndex = param.ValueStart;
                int       length     = param.ValueLength;
                var       buffer     = param.Value;
                Encoding  encoding   = null;
                Decoder   decoder    = null;
                Parameter parameter;
                string    value;

                if (param.Id.HasValue)
                {
                    method = ParameterEncodingMethod.Rfc2231;
                    parts  = rfc2231[param.Name];
                    parts.Sort();

                    value = string.Empty;

                    for (int i = 0; i < parts.Count; i++)
                    {
                        startIndex = parts[i].ValueStart;
                        length     = parts[i].ValueLength;
                        buffer     = parts[i].Value;

                        if (parts[i].Encoded)
                        {
                            bool     flush = i + 1 >= parts.Count || !parts[i + 1].Encoded;
                            Encoding charset;

                            // Note: Some mail clients mistakenly quote encoded parameter values when they shouldn't
                            if (length >= 2 && buffer[startIndex] == (byte)'"' && buffer[startIndex + length - 1] == (byte)'"')
                            {
                                startIndex++;
                                length -= 2;
                            }

                            value   += DecodeRfc2231(out charset, ref decoder, hex, buffer, startIndex, length, flush);
                            encoding = encoding ?? charset;
                        }
                        else if (length >= 2 && buffer[startIndex] == (byte)'"')
                        {
                            var quoted = CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            value += MimeUtils.Unquote(quoted);
                            hex.Reset();
                        }
                        else if (length > 0)
                        {
                            value += CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            hex.Reset();
                        }
                    }
                    hex.Reset();
                }
                else if (param.Encoded)
                {
                    // Note: param value is not supposed to be quoted, but issue #239 illustrates
                    // that this can happen in the wild. Hopefully we will not need to worry
                    // about quoted-pairs.
                    if (length >= 2 && buffer[startIndex] == (byte)'"')
                    {
                        if (buffer[startIndex + length - 1] == (byte)'"')
                        {
                            length--;
                        }

                        startIndex++;
                        length--;
                    }

                    value  = DecodeRfc2231(out encoding, ref decoder, hex, buffer, startIndex, length, true);
                    method = ParameterEncodingMethod.Rfc2231;
                    hex.Reset();
                }
                else if (!paramList.Contains(param.Name))
                {
                    // Note: If we've got an rfc2231-encoded version of the same parameter, then
                    // we'll want to choose that one as opposed to the ASCII variant (i.e. this one).
                    //
                    // While most mail clients that I know of do not send multiple parameters of the
                    // same name, rfc6266 suggests that HTTP servers are using this approach to work
                    // around HTTP clients that do not (yet) implement support for the rfc2231
                    // encoding of parameter values. Since none of the MIME specifications provide
                    // any suggestions for dealing with this, following rfc6266 seems to make the
                    // most sense, even though it is meant for HTTP clients and servers.
                    int codepage = -1;

                    if (length >= 2 && text[startIndex] == (byte)'"')
                    {
                        var quoted = Rfc2047.DecodeText(options, buffer, startIndex, length, out codepage);
                        value = MimeUtils.Unquote(quoted);
                    }
                    else if (length > 0)
                    {
                        value = Rfc2047.DecodeText(options, buffer, startIndex, length, out codepage);
                    }
                    else
                    {
                        value = string.Empty;
                    }

                    if (codepage != -1 && codepage != 65001)
                    {
                        encoding = CharsetUtils.GetEncoding(codepage);
                        method   = ParameterEncodingMethod.Rfc2047;
                    }
                }
                else
                {
                    continue;
                }

                if (paramList.table.TryGetValue(param.Name, out parameter))
                {
                    parameter.Encoding = encoding;
                    parameter.Value    = value;
                }
                else if (encoding != null)
                {
                    paramList.Add(encoding, param.Name, value);
                    parameter = paramList[paramList.Count - 1];
                }
                else
                {
                    paramList.Add(param.Name, value);
                    parameter = paramList[paramList.Count - 1];
                }

                parameter.EncodingMethod = method;
            }

            return(true);
        }
Example #21
0
        public void TestClearHeaders()
        {
            var message = new MimeMessage();

            message.Subject = "Clear the headers!";

            message.Sender = new MailboxAddress("Sender", "*****@*****.**");
            message.ReplyTo.Add(new MailboxAddress("Reply-To", "*****@*****.**"));
            message.From.Add(new MailboxAddress("From", "*****@*****.**"));
            message.To.Add(new MailboxAddress("To", "*****@*****.**"));
            message.Cc.Add(new MailboxAddress("Cc", "*****@*****.**"));
            message.Bcc.Add(new MailboxAddress("Bcc", "*****@*****.**"));
            message.MessageId = MimeUtils.GenerateMessageId();
            message.Date      = DateTimeOffset.Now;

            message.ResentSender = new MailboxAddress("Sender", "*****@*****.**");
            message.ResentReplyTo.Add(new MailboxAddress("Reply-To", "*****@*****.**"));
            message.ResentFrom.Add(new MailboxAddress("From", "*****@*****.**"));
            message.ResentTo.Add(new MailboxAddress("To", "*****@*****.**"));
            message.ResentCc.Add(new MailboxAddress("Cc", "*****@*****.**"));
            message.ResentBcc.Add(new MailboxAddress("Bcc", "*****@*****.**"));
            message.ResentMessageId = MimeUtils.GenerateMessageId();
            message.ResentDate      = DateTimeOffset.Now;

            message.Importance = MessageImportance.High;
            message.Priority   = MessagePriority.Urgent;

            message.References.Add("<id1@localhost>");
            message.InReplyTo = "<id1@localhost>";

            message.MimeVersion = new Version(1, 0);

            message.Headers.Clear();

            Assert.IsNull(message.Subject, "Subject has not been cleared.");

            Assert.IsNull(message.Sender, "Sender has not been cleared.");
            Assert.AreEqual(0, message.ReplyTo.Count, "Reply-To has not been cleared.");
            Assert.AreEqual(0, message.From.Count, "From has not been cleared.");
            Assert.AreEqual(0, message.To.Count, "To has not been cleared.");
            Assert.AreEqual(0, message.Cc.Count, "Cc has not been cleared.");
            Assert.AreEqual(0, message.Bcc.Count, "Bcc has not been cleared.");
            Assert.IsNull(message.MessageId, "Message-Id has not been cleared.");
            Assert.AreEqual(DateTimeOffset.MinValue, message.Date, "Date has not been cleared.");

            Assert.IsNull(message.ResentSender, "Resent-Sender has not been cleared.");
            Assert.AreEqual(0, message.ResentReplyTo.Count, "Resent-Reply-To has not been cleared.");
            Assert.AreEqual(0, message.ResentFrom.Count, "Resent-From has not been cleared.");
            Assert.AreEqual(0, message.ResentTo.Count, "Resent-To has not been cleared.");
            Assert.AreEqual(0, message.ResentCc.Count, "Resent-Cc has not been cleared.");
            Assert.AreEqual(0, message.ResentBcc.Count, "Resent-Bcc has not been cleared.");
            Assert.IsNull(message.ResentMessageId, "Resent-Message-Id has not been cleared.");
            Assert.AreEqual(DateTimeOffset.MinValue, message.ResentDate, "Resent-Date has not been cleared.");

            Assert.AreEqual(MessageImportance.Normal, message.Importance, "Importance has not been cleared.");
            Assert.AreEqual(MessagePriority.Normal, message.Priority, "Priority has not been cleared.");

            Assert.AreEqual(0, message.References.Count, "References has not been cleared.");
            Assert.IsNull(message.InReplyTo, "In-Reply-To has not been cleared.");

            Assert.IsNull(message.MimeVersion, "MIME-Version has not been cleared.");
        }
Example #22
0
        /// <summary>
        /// Splits the specified message into multiple messages.
        /// </summary>
        /// <remarks>
        /// Splits the specified message into multiple messages, each with a
        /// message/partial body no larger than the max size specified.
        /// </remarks>
        /// <returns>An enumeration of partial messages.</returns>
        /// <param name="message">The message.</param>
        /// <param name="maxSize">The maximum size for each message body.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="message"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// <paramref name="maxSize"/> is less than <c>1</c>.
        /// </exception>
        public static IEnumerable <MimeMessage> Split(MimeMessage message, int maxSize)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (maxSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(maxSize));
            }

            var memory = new MemoryStream();

            message.WriteTo(memory);
            memory.Seek(0, SeekOrigin.Begin);

            if (memory.Length <= maxSize)
            {
                memory.Dispose();

                yield return(message);

                yield break;
            }

            var streams = new List <Stream> ();

#if !NETSTANDARD1_3 && !NETSTANDARD1_6
            var buf = memory.GetBuffer();
#else
            var buf = memory.ToArray();
#endif
            long startIndex = 0;

            while (startIndex < memory.Length)
            {
                // Preferably, we'd split on whole-lines if we can,
                // but if that's not possible, split on max size
                long endIndex = Math.Min(memory.Length, startIndex + maxSize);

                if (endIndex < memory.Length)
                {
                    long ebx = endIndex;

                    while (ebx > (startIndex + 1) && buf[ebx] != (byte)'\n')
                    {
                        ebx--;
                    }

                    if (buf[ebx] == (byte)'\n')
                    {
                        endIndex = ebx + 1;
                    }
                }

                streams.Add(new BoundStream(memory, startIndex, endIndex, true));
                startIndex = endIndex;
            }

            var id     = message.MessageId ?? MimeUtils.GenerateMessageId();
            int number = 1;

            foreach (var stream in streams)
            {
                var part = new MessagePartial(id, number++, streams.Count);
                part.Content = new MimeContent(stream);

                var submessage = CloneMessage(message);
                submessage.MessageId = MimeUtils.GenerateMessageId();
                submessage.Body      = part;

                yield return(submessage);
            }

            yield break;
        }
Example #23
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ParameterList paramList)
        {
            var rfc2184 = new Dictionary <string, List <NameValuePair> > (StringComparer.OrdinalIgnoreCase);
            var @params = new List <NameValuePair> ();
            List <NameValuePair> parts;

            paramList = null;

            do
            {
                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (index >= endIndex)
                {
                    break;
                }

                // handle empty parameter name/value pairs
                if (text[index] == (byte)';')
                {
                    index++;
                    continue;
                }

                NameValuePair pair;
                if (!TryParseNameValuePair(options, text, ref index, endIndex, throwOnError, out pair))
                {
                    return(false);
                }

                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (pair.Id.HasValue)
                {
                    if (rfc2184.TryGetValue(pair.Name, out parts))
                    {
                        parts.Add(pair);
                    }
                    else
                    {
                        parts = new List <NameValuePair> ();
                        rfc2184[pair.Name] = parts;
                        @params.Add(pair);
                        parts.Add(pair);
                    }
                }
                else
                {
                    @params.Add(pair);
                }

                if (index >= endIndex)
                {
                    break;
                }

                if (text[index] != (byte)';')
                {
                    if (throwOnError)
                    {
                        throw new ParseException(string.Format("Invalid parameter list token at offset {0}", index), index, index);
                    }

                    return(false);
                }

                index++;
            } while (true);

            paramList = new ParameterList();
            var hex = new HexDecoder();

            foreach (var param in @params)
            {
                int     startIndex = param.ValueStart;
                int     length     = param.ValueLength;
                var     buffer     = param.Value;
                Decoder decoder    = null;
                string  value;

                if (param.Id.HasValue)
                {
                    parts = rfc2184[param.Name];
                    parts.Sort();

                    value = string.Empty;
                    for (int i = 0; i < parts.Count; i++)
                    {
                        startIndex = parts[i].ValueStart;
                        length     = parts[i].ValueLength;
                        buffer     = parts[i].Value;

                        if (parts[i].Encoded)
                        {
                            bool flush = i + 1 >= parts.Count || !parts[i + 1].Encoded;

                            // Note: Some mail clients mistakenly quote encoded parameter values when they shouldn't
                            if (length >= 2 && buffer[startIndex] == (byte)'"' && buffer[startIndex + length - 1] == (byte)'"')
                            {
                                startIndex++;
                                length -= 2;
                            }

                            value += DecodeRfc2184(ref decoder, hex, buffer, startIndex, length, flush);
                        }
                        else if (length >= 2 && buffer[startIndex] == (byte)'"')
                        {
                            var quoted = CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            value += MimeUtils.Unquote(quoted);
                            hex.Reset();
                        }
                        else if (length > 0)
                        {
                            value += CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            hex.Reset();
                        }
                    }
                    hex.Reset();
                }
                else if (param.Encoded)
                {
                    value = DecodeRfc2184(ref decoder, hex, buffer, startIndex, length, true);
                    hex.Reset();
                }
                else if (!paramList.Contains(param.Name))
                {
                    // Note: If we've got an rfc2184-encoded version of the same parameter, then
                    // we'll want to choose that one as opposed to the ASCII variant (i.e. this one).
                    //
                    // While most mail clients that I know of do not send multiple parameters of the
                    // same name, rfc6266 suggests that HTTP servers are using this approach to work
                    // around HTTP clients that do not (yet) implement support for the rfc2184/2231
                    // encoding of parameter values. Since none of the MIME specifications provide
                    // any suggestions for dealing with this, following rfc6266 seems to make the
                    // most sense, even though it is meant for HTTP clients and servers.
                    if (length >= 2 && text[startIndex] == (byte)'"')
                    {
                        var quoted = Rfc2047.DecodeText(options, buffer, startIndex, length);
                        value = MimeUtils.Unquote(quoted);
                    }
                    else if (length > 0)
                    {
                        value = Rfc2047.DecodeText(options, buffer, startIndex, length);
                    }
                    else
                    {
                        value = string.Empty;
                    }
                }
                else
                {
                    continue;
                }

                paramList[param.Name] = value;
            }

            return(true);
        }
        // This method using the Google API to send emails
        public static void sendEmailLessThanZero(string emailErrorResult)
        {
            Console.WriteLine("Trying to send an Email because error with {0} has occurred", emailErrorResult);

            // Declaring the email addresses used in this method, have not entered the correct emails addresses as for security reason
            // In a live version of this method the email addresses will be held in a more secure model
            string         youremailName      = "EnterName";
            string         youremailAddress   = "*****@*****.**";
            string         sendToName         = "EnterNameSendingto";
            string         sendToEmailAddress = "*****@*****.**";
            UserCredential credential;

            // A JSON secret file needs to be be generated in the Google API Manager to allow for authentication
            string locationGoogleClientSecretFile = "Enter location of the JSON Google API client secret file";

            using (var stream = new FileStream(locationGoogleClientSecretFile, FileMode.Open, FileAccess.Read))
            {
                string credPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                credPath   = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, new[] {
                    GmailService.Scope.MailGoogleCom,
                    GmailService.Scope.GmailCompose,
                    GmailService.Scope.GmailModify, GmailService.Scope.GmailSend
                },
                                                                         "user",
                                                                         CancellationToken.None,
                                                                         new FileDataStore(credPath, true)).Result;

                var service = new GmailService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName       = "GmailService API .NET Quickstart",
                });

                // The below code builds the message body of the mail, builder.HtmlBody can be used to build a HTML email if needed
                var message = new MimeMessage();
                message.From.Add(new MailboxAddress(youremailName, youremailAddress));
                message.To.Add(new MailboxAddress(sendToName, sendToEmailAddress));

                message.Subject = "An error has occurred with the calculations";
                var      builder  = new BodyBuilder();
                DateTime dateTime = DateTime.Now;
                string   strDate  = dateTime.ToString("HH:MM:ss, dddd, MMMM d, yyyy");

                builder.TextBody = @"An error has occurred with " + emailErrorResult + " at the followinf date time " + strDate;
                var contentId = MimeUtils.GenerateMessageId();

                // The email needs to be encoded before sending via the Google API
                message.Body = builder.ToMessageBody();
                var rawMessage = "";
                using (var streem = new MemoryStream())
                {
                    message.WriteTo(streem);
                    rawMessage = Convert.ToBase64String(streem.GetBuffer(), 0,
                                                        (int)streem.Length)
                                 .Replace('+', '-')
                                 .Replace('/', '_')
                                 .Replace("=", "");
                }

                var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
                {
                    Raw = rawMessage
                };

                // Send the encoded email and wrap in a Try Catch encase the email send is not successfully sent and report an erro has occured
                try
                {
                    service.Users.Messages.Send(gmailMessage, sendToEmailAddress).Execute();
                }
                catch (Exception e)
                {
                    Console.WriteLine("There was a problem sending the email via the Google Api");
                }
            }
        }
Example #25
0
        internal void Encode(StringBuilder builder)
        {
            builder.Append('(');

            if (Date.HasValue)
            {
                builder.AppendFormat("\"{0}\" ", DateUtils.FormatDate(Date.Value));
            }
            else
            {
                builder.Append("NIL ");
            }

            if (Subject != null)
            {
                builder.AppendFormat("{0} ", MimeUtils.Quote(Subject));
            }
            else
            {
                builder.Append("NIL ");
            }

            if (From.Count > 0)
            {
                EncodeAddressList(builder, From);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (Sender.Count > 0)
            {
                EncodeAddressList(builder, Sender);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (ReplyTo.Count > 0)
            {
                EncodeAddressList(builder, ReplyTo);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (To.Count > 0)
            {
                EncodeAddressList(builder, To);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (Cc.Count > 0)
            {
                EncodeAddressList(builder, Cc);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (Bcc.Count > 0)
            {
                EncodeAddressList(builder, Bcc);
                builder.Append(' ');
            }
            else
            {
                builder.Append("NIL ");
            }

            if (InReplyTo != null)
            {
                if (InReplyTo.Length > 1 && InReplyTo[0] != '<' && InReplyTo[InReplyTo.Length - 1] != '>')
                {
                    builder.AppendFormat("{0} ", MimeUtils.Quote('<' + InReplyTo + '>'));
                }
                else
                {
                    builder.AppendFormat("{0} ", MimeUtils.Quote(InReplyTo));
                }
            }
            else
            {
                builder.Append("NIL ");
            }

            if (MessageId != null)
            {
                if (MessageId.Length > 1 && MessageId[0] != '<' && MessageId[MessageId.Length - 1] != '>')
                {
                    builder.AppendFormat("{0}", MimeUtils.Quote('<' + MessageId + '>'));
                }
                else
                {
                    builder.AppendFormat("{0}", MimeUtils.Quote(MessageId));
                }
            }
            else
            {
                builder.Append("NIL");
            }

            builder.Append(')');
        }
Example #26
0
        /// <summary>
        /// This method is called when SIP message header reading has completed.
        /// </summary>
        /// <param name="asyncResult">An IAsyncResult that represents an asynchronous call.</param>
        private void BeginReadHeader_Completed(IAsyncResult asyncResult)
        {
            try
            {
                int countStored = m_pTcpSession.TcpStream.EndReadHeader(asyncResult);

                // We got CRLF(ping or pong).
                if (countStored == 0)
                {
                    // We have ping request.
                    if (IsServer)
                    {
                        // We have full ping request.
                        if (m_LastCRLF)
                        {
                            m_LastCRLF = false;

                            m_pStack.TransportLayer.OnMessageReceived(this,
                                                                      new[]
                            {
                                (byte)'\r', (byte)'\n',
                                (byte)'\r', (byte)'\n'
                            });
                        }
                        // We have first CRLF of ping request.
                        else
                        {
                            m_LastCRLF = true;
                        }
                    }
                    // We got pong to our ping request.
                    else
                    {
                        m_pStack.TransportLayer.OnMessageReceived(this, new[] { (byte)'\r', (byte)'\n' });
                    }

                    // Wait for new SIP message.
                    BeginReadHeader();
                }
                // We have SIP message header.
                else
                {
                    m_LastCRLF = false;

                    // Add header terminator blank line.
                    m_pMessage.Write(new[] { (byte)'\r', (byte)'\n' }, 0, 2);

                    m_pMessage.Position = 0;
                    string contentLengthValue = MimeUtils.ParseHeaderField("Content-Length:", m_pMessage);
                    m_pMessage.Position = m_pMessage.Length;

                    int contentLength = 0;

                    // Read message body.
                    if (contentLengthValue != "")
                    {
                        contentLength = Convert.ToInt32(contentLengthValue);
                    }

                    // Start reading message body.
                    if (contentLength > 0)
                    {
                        // Read body data.
                        m_pTcpSession.TcpStream.BeginReadFixedCount(m_pMessage,
                                                                    contentLength,
                                                                    BeginReadData_Completed,
                                                                    null);
                    }
                    // Message with no body.
                    else
                    {
                        byte[] messageData = m_pMessage.ToArray();
                        // Wait for new SIP message.
                        BeginReadHeader();

                        m_pStack.TransportLayer.OnMessageReceived(this, messageData);
                    }
                }
            }
            catch
            {
                Dispose();
            }
        }
Example #27
0
        static bool GetNextValue(string charset, Encoder encoder, HexEncoder hex, char[] chars, ref int index,
                                 ref byte[] bytes, ref byte[] encoded, int maxLength, out string value)
        {
            int length = chars.Length - index;

            if (length < maxLength)
            {
                switch (GetEncodeMethod(chars, index, length))
                {
                case EncodeMethod.Quote:
                    value  = MimeUtils.Quote(new string (chars, index, length));
                    index += length;
                    return(false);

                case EncodeMethod.None:
                    value  = new string (chars, index, length);
                    index += length;
                    return(false);
                }
            }

            length = Math.Min(maxLength, length);
            int ratio, count, n;

            do
            {
                count = encoder.GetByteCount(chars, index, length, true);
                if (count > maxLength && length > 1)
                {
                    ratio   = (int)Math.Round((double)count / (double)length);
                    length -= Math.Max((count - maxLength) / ratio, 1);
                    continue;
                }

                if (bytes.Length < count)
                {
                    Array.Resize <byte> (ref bytes, count);
                }

                count = encoder.GetBytes(chars, index, length, bytes, 0, true);

                // Note: the first chunk needs to be encoded in order to declare the charset
                if (index > 0 || charset == "us-ascii")
                {
                    var method = GetEncodeMethod(bytes, count);

                    if (method == EncodeMethod.Quote)
                    {
                        value  = MimeUtils.Quote(Encoding.ASCII.GetString(bytes, 0, count));
                        index += length;
                        return(false);
                    }

                    if (method == EncodeMethod.None)
                    {
                        value  = Encoding.ASCII.GetString(bytes, 0, count);
                        index += length;
                        return(false);
                    }
                }

                n = hex.EstimateOutputLength(count);
                if (encoded.Length < n)
                {
                    Array.Resize <byte> (ref encoded, n);
                }

                // only the first value gets a charset declaration
                int charsetLength = index == 0 ? charset.Length + 2 : 0;

                n = hex.Encode(bytes, 0, count, encoded);
                if (n > 3 && (charsetLength + n) > maxLength)
                {
                    int x = 0;

                    for (int i = n - 1; i >= 0 && charsetLength + i >= maxLength; i--)
                    {
                        if (encoded[i] == (byte)'%')
                        {
                            x--;
                        }
                        else
                        {
                            x++;
                        }
                    }

                    ratio   = (int)Math.Round((double)count / (double)length);
                    length -= Math.Max(x / ratio, 1);
                    continue;
                }

                if (index == 0)
                {
                    value = charset + "''" + Encoding.ASCII.GetString(encoded, 0, n);
                }
                else
                {
                    value = Encoding.ASCII.GetString(encoded, 0, n);
                }
                index += length;
                return(true);
            } while (true);
        }
Example #28
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out InternetAddress address)
        {
            address = null;

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            if (index == endIndex)
            {
                if (throwOnError)
                {
                    throw new ParseException("No address found.", index, index);
                }

                return(false);
            }

            // keep track of the start & length of the phrase
            int startIndex = index;
            int length     = 0;

            while (index < endIndex && ParseUtils.Skip8bitWord(text, ref index, endIndex, throwOnError))
            {
                length = index - startIndex;

                do
                {
                    if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                    {
                        return(false);
                    }

                    // Note: some clients don't quote dots in the name
                    if (index >= endIndex || text[index] != (byte)'.')
                    {
                        break;
                    }

                    index++;
                } while (true);
            }

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            // specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
            //             /  "," / ";" / ":" / "\" / <">  ;  string, to use
            //             /  "." / "[" / "]"              ;  within a word.

            if (index >= endIndex || text[index] == (byte)',' || text[index] == ';')
            {
                // we've completely gobbled up an addr-spec w/o a domain
                byte   sentinel = index < endIndex ? text[index] : (byte)',';
                string name, addrspec;

                // rewind back to the beginning of the local-part
                index = startIndex;

                if (!TryParseAddrspec(text, ref index, endIndex, sentinel, throwOnError, out addrspec))
                {
                    return(false);
                }

                ParseUtils.SkipWhiteSpace(text, ref index, endIndex);

                if (index < endIndex && text[index] == '(')
                {
                    int comment = index;

                    if (!ParseUtils.SkipComment(text, ref index, endIndex))
                    {
                        if (throwOnError)
                        {
                            throw new ParseException(string.Format("Incomplete comment token at offset {0}", comment), comment, index);
                        }

                        return(false);
                    }

                    comment++;

                    name = Rfc2047.DecodePhrase(options, text, comment, (index - 1) - comment).Trim();
                }
                else
                {
                    name = string.Empty;
                }

                address = new MailboxAddress(name, addrspec);

                return(true);
            }

            if (text[index] == (byte)':')
            {
                // rfc2822 group address
                int    codepage;
                string name;

                if (length > 0)
                {
                    name = Rfc2047.DecodePhrase(options, text, startIndex, length, out codepage);
                }
                else
                {
                    name     = string.Empty;
                    codepage = 65001;
                }

                return(TryParseGroup(options, text, startIndex, ref index, endIndex, MimeUtils.Unquote(name), codepage, throwOnError, out address));
            }

            if (text[index] == (byte)'<')
            {
                // rfc2822 angle-addr token
                int    codepage;
                string name;

                if (length > 0)
                {
                    name = Rfc2047.DecodePhrase(options, text, startIndex, length, out codepage);
                }
                else
                {
                    name     = string.Empty;
                    codepage = 65001;
                }

                return(TryParseMailbox(text, startIndex, ref index, endIndex, MimeUtils.Unquote(name), codepage, throwOnError, out address));
            }

            if (text[index] == (byte)'@')
            {
                // we're either in the middle of an addr-spec token or we completely gobbled up an addr-spec w/o a domain
                string name, addrspec;

                // rewind back to the beginning of the local-part
                index = startIndex;

                if (!TryParseAddrspec(text, ref index, endIndex, (byte)',', throwOnError, out addrspec))
                {
                    return(false);
                }

                ParseUtils.SkipWhiteSpace(text, ref index, endIndex);

                if (index < endIndex && text[index] == '(')
                {
                    int comment = index;

                    if (!ParseUtils.SkipComment(text, ref index, endIndex))
                    {
                        if (throwOnError)
                        {
                            throw new ParseException(string.Format("Incomplete comment token at offset {0}", comment), comment, index);
                        }

                        return(false);
                    }

                    comment++;

                    name = Rfc2047.DecodePhrase(options, text, comment, (index - 1) - comment).Trim();
                }
                else
                {
                    name = string.Empty;
                }

                address = new MailboxAddress(name, addrspec);

                return(true);
            }

            if (throwOnError)
            {
                throw new ParseException(string.Format("Invalid address token at offset {0}", startIndex), startIndex, index);
            }

            return(false);
        }
        public static void ProcessHtmlContent(BodyBuilder builder)
        {
            if (builder == null)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(builder.HtmlBody))
            {
                return;
            }

            try
            {
                var htmlDoc = new HtmlDocument();
                htmlDoc.Load(new MemoryStream(Encoding.UTF8.GetBytes(builder.HtmlBody)));

                if (htmlDoc.DocumentNode == null)
                {
                    return;
                }

                foreach (HtmlNode node in htmlDoc.DocumentNode.SelectNodes("//img[@src]"))
                {
                    var src = node.Attributes["src"].Value.Split('?', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();


                    if (!string.IsNullOrWhiteSpace(src) && src.StartsWith("/fs"))
                    {
                        try
                        {
                            Uri uri = new Uri(src);
                            src = uri.AbsolutePath;
                        }
                        catch { }

                        if (src.StartsWith("/fs"))
                        {
                            src = src.Substring(3);
                        }

                        DbFileRepository fsRepository = new DbFileRepository();
                        var file = fsRepository.Find(src);
                        if (file == null)
                        {
                            continue;
                        }

                        var bytes = file.GetBytes();

                        var extension = Path.GetExtension(src).ToLowerInvariant();
                        new FileExtensionContentTypeProvider().Mappings.TryGetValue(extension, out string mimeType);

                        var imagePart = new MimePart(mimeType)
                        {
                            ContentId               = MimeUtils.GenerateMessageId(),
                            Content                 = new MimeContent(new MemoryStream(bytes)),
                            ContentDisposition      = new ContentDisposition(ContentDisposition.Attachment),
                            ContentTransferEncoding = ContentEncoding.Base64,
                            FileName                = Path.GetFileName(src)
                        };

                        builder.LinkedResources.Add(imagePart);
                        node.SetAttributeValue("src", $"cid:{imagePart.ContentId}");
                    }
                }
                builder.HtmlBody = htmlDoc.DocumentNode.OuterHtml;
                if (string.IsNullOrWhiteSpace(builder.TextBody) && !string.IsNullOrWhiteSpace(builder.HtmlBody))
                {
                    builder.TextBody = ConvertToPlainText(builder.HtmlBody);
                }
            }
            catch
            {
                return;
            }
        }
Example #30
0
        /// <summary>
        /// Called when the headers change in some way.
        /// </summary>
        /// <remarks>
        /// <para>Whenever a header is added, changed, or removed, this method will
        /// be called in order to allow custom <see cref="MimeEntity"/> subclasses
        /// to update their state.</para>
        /// <para>Overrides of this method should call the base method so that their
        /// superclass may also update its own state.</para>
        /// </remarks>
        /// <param name="action">The type of change.</param>
        /// <param name="header">The header being added, changed or removed.</param>
        protected virtual void OnHeadersChanged(HeaderListChangedAction action, Header header)
        {
            string text;

            switch (action)
            {
            case HeaderListChangedAction.Added:
            case HeaderListChangedAction.Changed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    if (ContentDisposition.TryParse(Headers.Options, header.RawValue, out disposition))
                    {
                        disposition.Changed += ContentDispositionChanged;
                    }
                    break;

                case HeaderId.ContentLocation:
                    text = header.Value.Trim();

                    if (Uri.IsWellFormedUriString(text, UriKind.Absolute))
                    {
                        location = new Uri(text, UriKind.Absolute);
                    }
                    else if (Uri.IsWellFormedUriString(text, UriKind.Relative))
                    {
                        location = new Uri(text, UriKind.Relative);
                    }
                    else
                    {
                        location = null;
                    }
                    break;

                case HeaderId.ContentBase:
                    text = header.Value.Trim();

                    if (Uri.IsWellFormedUriString(text, UriKind.Absolute))
                    {
                        baseUri = new Uri(text, UriKind.Absolute);
                    }
                    else
                    {
                        baseUri = null;
                    }
                    break;

                case HeaderId.ContentId:
                    contentId = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault();
                    break;
                }
                break;

            case HeaderListChangedAction.Removed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    disposition = null;
                    break;

                case HeaderId.ContentLocation:
                    location = null;
                    break;

                case HeaderId.ContentBase:
                    baseUri = null;
                    break;

                case HeaderId.ContentId:
                    contentId = null;
                    break;
                }
                break;

            case HeaderListChangedAction.Cleared:
                if (disposition != null)
                {
                    disposition.Changed -= ContentDispositionChanged;
                }

                disposition = null;
                contentId   = null;
                location    = null;
                baseUri     = null;
                break;

            default:
                throw new ArgumentOutOfRangeException("action");
            }
        }