コード例 #1
0
        /// <summary>
        /// Initializes a populated instance of the OpaqueMail.ReadOnlyMailMessage class representing the message text passed in with attachments procesed according to the attachment filter flags.
        /// </summary>
        /// <param name="messageText">The raw contents of the e-mail message.</param>
        /// <param name="processingFlags">Flags determining whether specialized properties are returned with a ReadOnlyMailMessage.</param>
        /// <param name="parseExtendedHeaders">Whether to populate the ExtendedHeaders object.</param>
        public ReadOnlyMailMessage(string messageText, ReadOnlyMailMessageProcessingFlags processingFlags, bool parseExtendedHeaders)
        {
            if (((processingFlags & ReadOnlyMailMessageProcessingFlags.IncludeRawHeaders) > 0)
                && (processingFlags & ReadOnlyMailMessageProcessingFlags.IncludeRawBody) > 0)
                RawMessage = messageText;

            // Remember which specialized attachments to include.
            ProcessingFlags = processingFlags;

            // Fix messages whose carriage returns have been stripped.
            if (messageText.IndexOf("\r") < 0)
                messageText = messageText.Replace("\n", "\r\n");

            // Separate the headers for processing.
            string headers;
            int cutoff = messageText.IndexOf("\r\n\r\n");
            if (cutoff > -1)
                headers = messageText.Substring(0, cutoff);
            else
                headers = messageText;

            // Set the raw headers property if requested.
            if ((processingFlags & ReadOnlyMailMessageProcessingFlags.IncludeRawHeaders) > 0)
                RawHeaders = headers;

            // Calculate the size of the message.
            Size = messageText.Length;

            // Temporary header variables to be processed by Functions.FromMailAddressString() later.
            string fromText = "";
            string toText = "";
            string ccText = "";
            string bccText = "";
            string replyToText = "";
            string subjectText = "";

            // Temporary header variables to be processed later.
            List<string> receivedChain = new List<string>();
            string receivedText = "";

            // Unfold any unneeded whitespace, then loop through each line of the headers.
            string[] headersList = Functions.UnfoldWhitespace(headers).Replace("\r", "").Split('\n');
            foreach (string header in headersList)
            {
                // Split header {name:value} pairs by the first colon found.
                int colonPos = header.IndexOf(":");
                if (colonPos > -1 && colonPos < header.Length - 1)
                {
                    string[] headerParts = new string[] { header.Substring(0, colonPos), header.Substring(colonPos + 1).TrimStart(new char[] { ' ' }) };
                    string headerType = headerParts[0].ToLower();
                    string headerValue = headerParts[1];

                    // Set header variables for common headers.
                    if (!string.IsNullOrEmpty(headerType) && !string.IsNullOrEmpty(headerValue))
                        Headers[headerParts[0]] = headerValue;

                    switch (headerType)
                    {
                        case "cc":
                            if (ccText.Length > 0)
                                ccText += ", ";
                            ccText = headerValue;
                            break;
                        case "content-transfer-encoding":
                            ContentTransferEncoding = headerValue;
                            switch (headerValue.ToLower())
                            {
                                case "base64":
                                    BodyTransferEncoding = TransferEncoding.Base64;
                                    break;
                                case "quoted-printable":
                                    BodyTransferEncoding = TransferEncoding.QuotedPrintable;
                                    break;
                                case "7bit":
                                    BodyTransferEncoding = TransferEncoding.SevenBit;
                                    break;
                                case "8bit":
                                    BodyTransferEncoding = TransferEncoding.EightBit;
                                    break;
                                default:
                                    BodyTransferEncoding = TransferEncoding.Unknown;
                                    break;
                            }
                            break;
                        case "content-language":
                            ContentLanguage = headerValue;
                            break;
                        case "content-type":
                            // If multiple content-types are passed, only process the first.
                            if (string.IsNullOrEmpty(ContentType))
                            {
                                ContentType = headerValue.Trim();
                                CharSet = Functions.ExtractMimeParameter(ContentType, "charset");
                            }
                            break;
                        case "date":
                            string dateString = headerValue;

                            // Ignore extraneous datetime information.
                            int dateStringParenthesis = dateString.IndexOf("(");
                            if (dateStringParenthesis > -1)
                                dateString = dateString.Substring(0, dateStringParenthesis - 1);

                            // Remove timezone suffix.
                            if (dateString.Substring(dateString.Length - 4, 1) == " ")
                                dateString = dateString.Substring(0, dateString.Length - 4);

                            DateTime.TryParse(dateString, out Date);
                            break;
                        case "delivered-to":
                            DeliveredTo = headerValue;
                            break;
                        case "from":
                            fromText = headerValue;
                            break;
                        case "importance":
                            Importance = headerValue;
                            break;
                        case "in-reply-to":
                            // Ignore opening and closing <> characters.
                            InReplyTo = headerValue;
                            if (InReplyTo.StartsWith("<"))
                                InReplyTo = InReplyTo.Substring(1);
                            if (InReplyTo.EndsWith(">"))
                                InReplyTo = InReplyTo.Substring(0, InReplyTo.Length - 1);
                            break;
                        case "message-id":
                            // Ignore opening and closing <> characters.
                            MessageId = headerValue;
                            if (MessageId.StartsWith("<"))
                                MessageId = MessageId.Substring(1);
                            if (MessageId.EndsWith(">"))
                                MessageId = MessageId.Substring(0, MessageId.Length - 1);
                            break;
                        case "received":
                        case "x-received":
                            if (!string.IsNullOrEmpty(receivedText))
                                receivedChain.Add(receivedText);

                            receivedText = headerValue;
                            break;
                        case "replyto":
                        case "reply-to":
                            replyToText = headerValue;
                            break;
                        case "return-path":
                            // Ignore opening and closing <> characters.
                            ReturnPath = headerValue;
                            if (ReturnPath.StartsWith("<"))
                                ReturnPath = ReturnPath.Substring(1);
                            if (ReturnPath.EndsWith(">"))
                                ReturnPath = ReturnPath.Substring(0, ReturnPath.Length - 1);
                            break;
                        case "sender":
                        case "x-sender":
                            if (headerValue.Length > 0)
                            {
                                MailAddressCollection senderCollection = Functions.FromMailAddressString(headerValue);
                                if (senderCollection.Count > 0)
                                    this.Sender = senderCollection[0];
                            }
                            break;
                        case "subject":
                            subjectText = headerValue;
                            break;
                        case "to":
                            if (toText.Length > 0)
                                toText += ", ";
                            toText += headerValue;
                            break;
                        case "x-priority":
                            switch (headerValue.ToUpper())
                            {
                                case "LOW":
                                    Priority = MailPriority.Low;
                                    break;
                                case "NORMAL":
                                    Priority = MailPriority.Normal;
                                    break;
                                case "HIGH":
                                    Priority = MailPriority.High;
                                    break;
                            }
                            break;
                        case "x-subject-encryption":
                            bool.TryParse(headerValue, out SubjectEncryption);
                            break;
                        default:
                            break;
                    }

                    // Set header variables for advanced headers.
                    if (parseExtendedHeaders)
                    {
                        ExtendedProperties = new ExtendedProperties();

                        switch (headerType)
                        {
                            case "acceptlanguage":
                            case "accept-language":
                                ExtendedProperties.AcceptLanguage = headerValue;
                                break;
                            case "authentication-results":
                                ExtendedProperties.AuthenticationResults = headerValue;
                                break;
                            case "bounces-to":
                            case "bounces_to":
                                ExtendedProperties.BouncesTo = headerValue;
                                break;
                            case "content-description":
                                ExtendedProperties.ContentDescription = headerValue;
                                break;
                            case "dispositionnotificationto":
                            case "disposition-notification-to":
                                ExtendedProperties.DispositionNotificationTo = headerValue;
                                break;
                            case "dkim-signature":
                            case "domainkey-signature":
                            case "x-google-dkim-signature":
                                ExtendedProperties.DomainKeySignature = headerValue;
                                break;
                            case "domainkey-status":
                                ExtendedProperties.DomainKeyStatus = headerValue;
                                break;
                            case "errors-to":
                                ExtendedProperties.ErrorsTo = headerValue;
                                break;
                            case "list-unsubscribe":
                            case "x-list-unsubscribe":
                                ExtendedProperties.ListUnsubscribe = headerValue;
                                break;
                            case "mailer":
                            case "x-mailer":
                                ExtendedProperties.Mailer = headerValue;
                                break;
                            case "organization":
                            case "x-originator-org":
                            case "x-originatororg":
                            case "x-organization":
                                ExtendedProperties.OriginatorOrg = headerValue;
                                break;
                            case "original-messageid":
                            case "x-original-messageid":
                                ExtendedProperties.OriginalMessageId = headerValue;
                                break;
                            case "originating-email":
                            case "x-originating-email":
                                ExtendedProperties.OriginatingEmail = headerValue;
                                break;
                            case "precedence":
                                ExtendedProperties.Precedence = headerValue;
                                break;
                            case "received-spf":
                                ExtendedProperties.ReceivedSPF = headerValue;
                                break;
                            case "references":
                                ExtendedProperties.References = headerValue;
                                break;
                            case "resent-date":
                                string dateString = headerValue;

                                // Ignore extraneous datetime information.
                                int dateStringParenthesis = dateString.IndexOf("(");
                                if (dateStringParenthesis > -1)
                                    dateString = dateString.Substring(0, dateStringParenthesis - 1);

                                // Remove timezone suffix.
                                if (dateString.Substring(dateString.Length - 4) == " ")
                                    dateString = dateString.Substring(0, dateString.Length - 4);

                                DateTime.TryParse(dateString, out ExtendedProperties.ResentDate);
                                break;
                            case "resent-from":
                                ExtendedProperties.ResentFrom = headerValue;
                                break;
                            case "resent-message-id":
                                ExtendedProperties.ResentMessageID = headerValue;
                                break;
                            case "thread-index":
                                ExtendedProperties.ThreadIndex = headerValue;
                                break;
                            case "thread-topic":
                                ExtendedProperties.ThreadTopic = headerValue;
                                break;
                            case "user-agent":
                            case "useragent":
                                ExtendedProperties.UserAgent = headerValue;
                                break;
                            case "x-auto-response-suppress":
                                ExtendedProperties.AutoResponseSuppress = headerValue;
                                break;
                            case "x-campaign":
                            case "x-campaign-id":
                            case "x-campaignid":
                            case "x-mllistcampaign":
                            case "x-rpcampaign":
                                ExtendedProperties.CampaignID = headerValue;
                                break;
                            case "x-delivery-context":
                                ExtendedProperties.DeliveryContext = headerValue;
                                break;
                            case "x-maillist-id":
                                ExtendedProperties.MailListId = headerValue;
                                break;
                            case "x-msmail-priority":
                                ExtendedProperties.MSMailPriority = headerValue;
                                break;
                            case "x-originalarrivaltime":
                            case "x-original-arrival-time":
                                dateString = headerValue;

                                // Ignore extraneous datetime information.
                                dateStringParenthesis = dateString.IndexOf("(");
                                if (dateStringParenthesis > -1)
                                    dateString = dateString.Substring(0, dateStringParenthesis - 1);

                                // Remove timezone suffix.
                                if (dateString.Substring(dateString.Length - 4) == " ")
                                    dateString = dateString.Substring(0, dateString.Length - 4);

                                DateTime.TryParse(dateString, out ExtendedProperties.OriginalArrivalTime);
                                break;
                            case "x-originating-ip":
                                ExtendedProperties.OriginatingIP = headerValue;
                                break;
                            case "x-rcpt-to":
                                if (headerValue.Length > 1)
                                    ExtendedProperties.RcptTo = headerValue.Substring(1, headerValue.Length - 2);
                                break;
                            case "x-csa-complaints":
                            case "x-complaints-to":
                            case "x-reportabuse":
                            case "x-report-abuse":
                            case "x-mail_abuse_inquiries":
                                ExtendedProperties.ReportAbuse = headerValue;
                                break;
                            case "x-spam-score":
                                ExtendedProperties.SpamScore = headerValue;
                                break;
                            default:
                                break;
                        }
                    }
                }
            }

            // Track all Received and X-Received headers.
            if (!string.IsNullOrEmpty(receivedText))
                receivedChain.Add(receivedText);
            ReceivedChain = receivedChain.ToArray();

            // Process the body if it's passed in.
            string body = "";
            if (cutoff > -1)
                 body = messageText.Substring(cutoff + 2);
            if (!string.IsNullOrEmpty(body))
            {
                // Set the raw body property if requested.
                if ((processingFlags & ReadOnlyMailMessageProcessingFlags.IncludeRawBody) > 0)
                    RawBody = body;

                // Parse body into MIME parts.
                List<MimePart> mimeParts = MimePart.ExtractMIMEParts(ContentType, CharSet, ContentTransferEncoding, body, ProcessingFlags);

                // Process each MIME part.
                if (mimeParts.Count > 0)
                {
                    // Keep track of S/MIME signing and envelope encryption.
                    bool allMimePartsSigned = true, allMimePartsEncrypted = true, allMimePartsTripleWrapped = true;

                    // Process each MIME part.
                    for (int j = 0; j < mimeParts.Count; j++)
                    {
                        MimePart mimePart = mimeParts[j];

                        int semicolon = mimePart.ContentType.IndexOf(";");
                        if (semicolon > -1)
                        {
                            string originalContentType = mimePart.ContentType;
                            mimePart.ContentType = mimePart.ContentType.Substring(0, semicolon);

                            if (mimePart.ContentType.ToUpper() == "MESSAGE/PARTIAL")
                            {
                                PartialMessageId = Functions.ExtractMimeParameter(originalContentType, "id");
                                int partialMessageNumber = 0;
                                if (int.TryParse(Functions.ExtractMimeParameter(originalContentType, "number"), out partialMessageNumber))
                                    PartialMessageNumber = partialMessageNumber;
                            }
                        }

                        // Extract any signing certificates.  If this MIME part isn't signed, the overall message isn't signed.
                        if (mimePart.SmimeSigned)
                        {
                            if (mimePart.SmimeSigningCertificates.Count > 0 && SmimeSigningCertificate == null)
                            {
                                foreach (X509Certificate2 signingCert in mimePart.SmimeSigningCertificates)
                                {
                                    if (!SmimeSigningCertificateChain.Contains(signingCert))
                                    {
                                        SmimeSigningCertificateChain.Add(signingCert);
                                        SmimeSigningCertificate = signingCert;
                                    }
                                }
                            }
                        }
                        else
                            allMimePartsSigned = false;

                        // If this MIME part isn't marked as being in an encrypted envelope, the overall message isn't encrypted.
                        if (!mimePart.SmimeEncryptedEnvelope)
                        {
                            // Ignore signatures and encryption blocks when determining if everything is encrypted.
                            if (!mimePart.ContentType.StartsWith("application/pkcs7-signature") && !mimePart.ContentType.StartsWith("application/x-pkcs7-signature") && !mimePart.ContentType.StartsWith("application/pkcs7-mime"))
                                allMimePartsEncrypted = false;
                        }

                        // If this MIME part isn't marked as being triple wrapped, the overall message isn't triple wrapped.
                        if (!mimePart.SmimeTripleWrapped)
                        {
                            // Ignore signatures and encryption blocks when determining if everything is triple wrapped.
                            if (!mimePart.ContentType.StartsWith("application/pkcs7-signature") && !mimePart.ContentType.StartsWith("application/x-pkcs7-signature") && !mimePart.ContentType.StartsWith("application/pkcs7-mime"))
                                allMimePartsTripleWrapped = false;
                        }

                        // Set the default primary body, defaulting to text/html and falling back to any text/*.
                        string contentTypeToUpper = mimePart.ContentType.ToUpper();
                        if (Body.Length < 1)
                        {
                            // If the MIME part is of type text/*, set it as the intial message body.
                            if (string.IsNullOrEmpty(mimePart.ContentType) || contentTypeToUpper.StartsWith("TEXT/"))
                            {
                                IsBodyHtml = contentTypeToUpper.StartsWith("TEXT/HTML");
                                Body = mimePart.Body;
                                CharSet = mimePart.CharSet;
                                ContentType = mimePart.ContentType;
                                if (mimePart.ContentTransferEncoding != TransferEncoding.Unknown)
                                    BodyTransferEncoding = mimePart.ContentTransferEncoding;
                            }
                            else
                            {
                                // If the MIME part isn't of type text/*, treat is as an attachment.
                                MemoryStream attachmentStream = new MemoryStream(mimePart.BodyBytes);
                                Attachment attachment;
                                if (mimePart.ContentType.IndexOf("/") > -1)
                                    attachment = new Attachment(attachmentStream, mimePart.Name, mimePart.ContentType);
                                else
                                    attachment = new Attachment(attachmentStream, mimePart.Name);

                                attachment.ContentId = mimePart.ContentID;
                                Attachments.Add(attachment);
                            }
                        }
                        else
                        {
                            // If the current body isn't text/html and this is, replace the default body with the current MIME part.
                            if (!ContentType.ToUpper().StartsWith("TEXT/HTML") && contentTypeToUpper.StartsWith("TEXT/HTML"))
                            {
                                // Add the previous default body as an alternate view.
                                MemoryStream alternateViewStream = new MemoryStream(Encoding.UTF8.GetBytes(Body));
                                AlternateView alternateView = new AlternateView(alternateViewStream, ContentType);
                                if (BodyTransferEncoding != TransferEncoding.Unknown)
                                    alternateView.TransferEncoding = BodyTransferEncoding;
                                AlternateViews.Add(alternateView);

                                IsBodyHtml = true;
                                Body = mimePart.Body;
                                CharSet = mimePart.CharSet;
                                ContentType = mimePart.ContentType;
                                if (mimePart.ContentTransferEncoding != TransferEncoding.Unknown)
                                    BodyTransferEncoding = mimePart.ContentTransferEncoding;
                            }
                            else
                            {
                                // If the MIME part isn't of type text/*, treat is as an attachment.
                                MemoryStream attachmentStream = new MemoryStream(mimePart.BodyBytes);
                                Attachment attachment;
                                if (mimePart.ContentType.IndexOf("/") > -1)
                                    attachment = new Attachment(attachmentStream, mimePart.Name, mimePart.ContentType);
                                else
                                    attachment = new Attachment(attachmentStream, mimePart.Name);
                                attachment.ContentId = mimePart.ContentID;
                                Attachments.Add(attachment);
                            }
                        }
                    }

                    // OpaqueMail optional setting for protecting the subject.
                    if (SubjectEncryption && Body.StartsWith("Subject: "))
                    {
                        int linebreakPosition = Body.IndexOf("\r\n");
                        if (linebreakPosition > -1)
                        {
                            subjectText = Body.Substring(9, linebreakPosition - 9);
                            Body = Body.Substring(linebreakPosition + 2);
                        }
                    }

                    // Set the message's S/MIME attributes.
                    SmimeSigned = allMimePartsSigned;
                    SmimeEncryptedEnvelope = allMimePartsEncrypted;
                    SmimeTripleWrapped = allMimePartsTripleWrapped;
                }
                else
                {
                    // Process non-MIME messages.
                    Body = body;
                }
            }

            // Parse String representations of addresses into MailAddress objects.
            if (fromText.Length > 0)
            {
                MailAddressCollection fromAddresses = Functions.FromMailAddressString(fromText);
                if (fromAddresses.Count > 0)
                    From = fromAddresses[0];
            }

            if (toText.Length > 0)
            {
                To.Clear();
                MailAddressCollection toAddresses = Functions.FromMailAddressString(toText);
                foreach (MailAddress toAddress in toAddresses)
                    To.Add(toAddress);

                // Add the address to the AllRecipients collection.
                foreach (MailAddress toAddress in toAddresses)
                {
                    if (!AllRecipients.Contains(toAddress.Address))
                        AllRecipients.Add(toAddress.Address);
                }
            }

            if (ccText.Length > 0)
            {
                CC.Clear();
                MailAddressCollection ccAddresses = Functions.FromMailAddressString(ccText);
                foreach (MailAddress ccAddress in ccAddresses)
                    CC.Add(ccAddress);

                // Add the address to the AllRecipients collection.
                foreach (MailAddress ccAddress in ccAddresses)
                {
                    if (!AllRecipients.Contains(ccAddress.Address))
                        AllRecipients.Add(ccAddress.Address);
                }
            }

            if (bccText.Length > 0)
            {
                Bcc.Clear();
                MailAddressCollection bccAddresses = Functions.FromMailAddressString(bccText);
                foreach (MailAddress bccAddress in bccAddresses)
                    Bcc.Add(bccAddress);

                // Add the address to the AllRecipients collection.
                foreach (MailAddress bccAddress in bccAddresses)
                {
                    if (!AllRecipients.Contains(bccAddress.Address))
                        AllRecipients.Add(bccAddress.Address);
                }
            }

            if (replyToText.Length > 0)
            {
                ReplyToList.Clear();
                MailAddressCollection replyToAddresses = Functions.FromMailAddressString(replyToText);
                foreach (MailAddress replyToAddress in replyToAddresses)
                    ReplyToList.Add(replyToAddress);
            }

            // Decode international strings and remove escaped linebreaks.
            Subject = Functions.DecodeMailHeader(subjectText).Replace("\r", "").Replace("\n", "");
        }