Пример #1
0
        public bool ProcessEmbedded(ref RxMailMessage Message)
        {
            //raw email tracing
            if (isGetRawEmail)
            {
                isTraceRawEmail = true;
                if (RawEmailSB == null)
                {
                    RawEmailSB = new StringBuilder(100000);
                }
                else
                {
                    RawEmailSB.Length = 0;
                }
            }

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");

            if (isGetRawEmail)
            {
                //add raw email version to message
                Message.RawContent = RawEmailSB.ToString();
                isTraceRawEmail    = false;
            }

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete || MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                TraceFrom("email with {0} body chars received", Message.Body.Length);
                return(true);
            }
            return(false);
        }
Пример #2
0
        /// <summary>
        /// Gets 1 email from POP3 server and processes it.
        /// </summary>
        /// <param name="MessageNo">Email Id to be fetched from POP3 server</param>
        /// <param name="Message">decoded email</param>
        /// <returns>false: no email received or email not properly formatted</returns>
        public bool GetEmail(int MessageNo, out RxMailMessage Message)
        {
            Message = null;

            //request email, send RETRieve command to POP3 server
            if (!SendRetrCommand(MessageNo))
            {
                return(false);
            }

            //prepare message, set defaults as specified in RFC 2046
            //although they get normally overwritten, we have to make sure there are at least defaults
            Message = new RxMailMessage();
            Message.ContentTransferEncoding = TransferEncoding.SevenBit;
            Message.TransferType            = "7bit";
            this.messageNo = MessageNo;

            //raw email tracing
            if (isGetRawEmail)
            {
                isTraceRawEmail = true;
                if (RawEmailSB == null)
                {
                    RawEmailSB = new StringBuilder(100000);
                }
                else
                {
                    RawEmailSB.Length = 0;
                }
            }

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");

            if (isGetRawEmail)
            {
                //add raw email version to message
                Message.RawContent = RawEmailSB.ToString();
                isTraceRawEmail    = false;
            }

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete ||
                MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                TraceFrom("email with {0} body chars received", Message.Body.Length);
                return(true);
            }
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Gets an email from the supplied Email Stream and processes it.
        /// </summary>
        /// <param name="sEmlPath">Stream that designates the an Email stream</param>
        /// <returns>RxMailMessage or null if email not properly formatted</returns>
        public RxMailMessage GetEmail(Stream EmailStream)
        {
            DATA_TEXT = null;

            EmailStreamReader = new StreamReader(EmailStream, Encoding.ASCII);

            RxMailMessage Message = new RxMailMessage();

            Message.ContentTransferEncoding = TransferEncoding.SevenBit;
            Message.TransferType            = "7bit";

            RxMailMessage Root = new RxMailMessage();

            Root.ContentTransferEncoding = TransferEncoding.SevenBit;
            Root.TransferType            = "7bit";

            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Root, Message, "");

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete || MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                if (Root.To.Count == 0)
                {
                    string sTo = Root.Headers["x-receiver"];
                    if (!string.IsNullOrEmpty(sTo))
                    {
                        Root.To.Add(sTo);
                    }
                }

                if (Root.From == null)
                {
                    string sFrom = Root.Headers["x-sender"];
                    if (!string.IsNullOrEmpty(sFrom))
                    {
                        Root.From = new MailAddress(sFrom);
                    }
                }

                foreach (string key in Message.Headers)
                {
                    Root.Headers[key] = Message.Headers[key];
                }

                return(Root);
            }

            return(null);
        }
        /// <summary>
        /// Gets an email from the supplied Email Stream and processes it.
        /// </summary>
        /// <param name="sEmlPath">Stream that designates the an Email stream</param>
        /// <returns>RxMailMessage or null if email not properly formatted</returns>
        public RxMailMessage GetEmail(Stream EmailStream)
        {
            EmailStreamReader = new StreamReader(EmailStream, Encoding.ASCII);

            //prepare message, set defaults as specified in RFC 2046
            //although they get normally overwritten, we have to make sure there are at least defaults
            RxMailMessage Message = new RxMailMessage();

            Message.ContentTransferEncoding = TransferEncoding.SevenBit;
            Message.TransferType            = "7bit";

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete || MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                // I've seen EML files that don't have a "To: entity but have "x-receiver:" entity set to the recipient. check and use that if need be
                if (Message.To.Count == 0)
                {
                    // do something with
                    string sTo = Message.Headers["x-receiver"];
                    if (!string.IsNullOrEmpty(sTo))
                    {
                        Message.To.Add(sTo);
                    }
                }

                // From: maybe also but never have seen it missing
                if (Message.From == null)
                {
                    // do something with
                    string sFrom = Message.Headers["x-sender"];
                    if (!string.IsNullOrEmpty(sFrom))
                    {
                        Message.From = new MailAddress(sFrom);
                    }
                }

                //TraceFrom("email with {0} body chars received", Message.Body.Length);
                return(Message);
            }
            return(null);
        }
Пример #5
0
        /// <summary>
        /// Gets an email from the supplied Email Stream and processes it.
        /// </summary>
        /// <param name="emailStream">The email stream object</param>
        /// <returns>
        /// MailMessageParser or null if email not properly formatted
        /// </returns>
        public MailMessageParser GetEmail(Stream emailStream)
        {
            this.EmailStreamReader = new StreamReader(emailStream, Encoding.ASCII);

            ////prepare message, set defaults as specified in RFC 2046
            MailMessageParser message = new MailMessageParser();

            message.ContentTransferEncoding = TransferEncoding.SevenBit;
            MailMessageParser    result = null;
            MimeEntityReturnCode messageMimeReturnCode = this.ProcessMimeEntity(message, string.Empty);

            if (messageMimeReturnCode == MimeEntityReturnCode.bodyComplete || messageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                if (0 == message.To.Count)
                {
                    string toField = message.Headers[ServiceConstants.Mail_Message_Receiver_Header];
                    if (!string.IsNullOrEmpty(toField))
                    {
                        message.To.Add(toField);
                    }
                }

                if (null == message.From)
                {
                    string mailFrom = message.Headers[ServiceConstants.Mail_Message_Sender_Header];
                    if (!string.IsNullOrEmpty(mailFrom))
                    {
                        message.From = new MailAddress(mailFrom);
                    }
                }

                result = message;
            }

            return(result);
        }
Пример #6
0
 /// <summary>
 /// Check if the response line received is a parent boundary 
 /// </summary>
 private bool parentBoundaryFound(string response, string parentBoundaryStart, string parentBoundaryEnd, out MimeEntityReturnCode boundaryMimeReturnCode)
 {
     boundaryMimeReturnCode = MimeEntityReturnCode.undefined;
       if (response==null || response.Length<2 || response[0]!='-' || response[1]!='-') {
     //quick test: reponse doesn't start with "--", so cannot be a separator line
     return false;
       }
       if (response==parentBoundaryStart) {
     boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryStartFound;
     return true;
       } else if (response==parentBoundaryEnd) {
     boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryEndFound;
     return true;
       }
       return false;
 }
Пример #7
0
 /// <summary>
 /// Check if the response line received is a parent boundary
 /// </summary>
 private bool parentBoundaryFound(string response, string parentBoundaryStart, string parentBoundaryEnd, out MimeEntityReturnCode boundaryMimeReturnCode)
 {
     boundaryMimeReturnCode = MimeEntityReturnCode.undefined;
     if (response == null || response.Length < 2 || response[0] != '-' || response[1] != '-')
     {
         //quick test: reponse doesn't start with "--", so cannot be a separator line
         return(false);
     }
     if (response == parentBoundaryStart)
     {
         boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryStartFound;
         return(true);
     }
     else if (response == parentBoundaryEnd)
     {
         boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryEndFound;
         return(true);
     }
     return(false);
 }
Пример #8
0
        /// <summary>
        /// Check if the response line received is a parent boundary
        /// </summary>
        /// <param name="response">mail response line</param>
        /// <param name="parentBoundaryStart"> parent boundary start identifier</param>
        /// <param name="parentBoundaryEnd">parent boundary end identifier</param>
        /// <param name="boundaryMimeReturnCode">boundary MIME return code.</param>
        /// <returns>
        /// If parent boundary found then true or false
        /// </returns>
        private static bool ParentBoundaryFound(string response, string parentBoundaryStart, string parentBoundaryEnd, out MimeEntityReturnCode boundaryMimeReturnCode)
        {
            bool result = false;
            boundaryMimeReturnCode = MimeEntityReturnCode.undefined;
            if (null == response || 2 > response.Length || '-' != response[0] || '-' != response[1])
            {
                result = false;
            }

            else if (response == parentBoundaryStart)
            {
                boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryStartFound;
                result = true;
            }
            else if (response == parentBoundaryEnd)
            {
                boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryEndFound;
                result = true;
            }

            return result;
        }
Пример #9
0
                private MimeEntityReturnCode ProcessDelimitedBody(RxMailMessage message, string BoundaryStart, string parentBoundaryStart, string parentBoundaryEnd)
                {
                    string response = string.Empty;

                    if (BoundaryStart.Trim() == parentBoundaryStart.Trim())
                    {
                        //Mime entity boundaries have to be unique
                        callGetEmailWarning("new boundary same as parent boundary: \'{0}\'", parentBoundaryStart);
                        //empty this message
                        while (readMultiLine(ref response))
                        {
                        }
                        return MimeEntityReturnCode.problem;
                    }

                    //
                    MimeEntityReturnCode ReturnCode = new MimeEntityReturnCode();
                    do
                    {

                        //empty StringBuilder
                        MimeEntitySB.Length = 0;
                        RxMailMessage ChildPart = message.CreateChildEntity();

                        //recursively call MIME part processing
                        ReturnCode = ProcessMimeEntity(ChildPart, BoundaryStart);

                        if (ReturnCode == MimeEntityReturnCode.problem)
                        {
                            //it seems the received email doesn't follow the MIME specification. Stop here
                            return MimeEntityReturnCode.problem;
                        }

                        //add the newly found child MIME part to the parent
                        AddChildPartsToParent(ChildPart, message);
                    } while (ReturnCode != MimeEntityReturnCode.parentBoundaryEndFound);

                    //disregard all future lines until parent boundary is found or end of complete message
                    MimeEntityReturnCode boundaryMimeReturnCode = new MimeEntityReturnCode();
                    bool hasParentBoundary = parentBoundaryStart.Length > 0;
                    while (readMultiLine(ref response))
                    {
                        if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, ref boundaryMimeReturnCode))
                        {
                            return boundaryMimeReturnCode;
                        }
                    }

                    return MimeEntityReturnCode.bodyComplete;
                }
Пример #10
0
                /// <summary>
                /// Process a MIME entity
                ///
                /// A MIME entity consists of header and body.
                /// Separator lines in the body might mark children MIME entities
                /// </summary>
                private MimeEntityReturnCode ProcessMimeEntity(RxMailMessage message, string parentBoundaryStart)
                {
                    bool hasParentBoundary = parentBoundaryStart.Length > 0;
                    string parentBoundaryEnd = parentBoundaryStart + "--";
                    MimeEntityReturnCode boundaryMimeReturnCode = new MimeEntityReturnCode();

                    //some format fields are inherited from parent, only the default for
                    //ContentType needs to be set here, otherwise the boundary parameter would be
                    //inherited too !
                    message.SetContentTypeFields("text/plain; charset=us-ascii");

                    //get header
                    //----------
                    string completeHeaderField = null; //consists of one start line and possibly several continuation lines
                    string response = string.Empty;

                    // read header lines until empty line is found (end of header)
                    while (true)
                    {
                        if (! readMultiLine(ref response))
                        {
                            //POP3 server has not send any more lines
                            callGetEmailWarning("incomplete MIME entity header received", null);
                            //empty this message
                            while (readMultiLine(ref response))
                            {
                            }
                            System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                            return MimeEntityReturnCode.problem;
                        }

                        if (response.Length < 1)
                        {
                            //empty line found => end of header
                            if (completeHeaderField != null)
                            {
                                ProcessHeaderField(message, completeHeaderField);
                            }
                            else
                            {
                                //there was only an empty header.
                            }
                            break;
                        }

                        //check if there is a parent boundary in the header (wrong format!)
                        if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, ref boundaryMimeReturnCode))
                        {
                            callGetEmailWarning("MIME entity header  prematurely ended by parent boundary", null);
                            //empty this message
                            while (readMultiLine(ref response))
                            {
                            }
                            System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                            return boundaryMimeReturnCode;
                        }
                        //read header field
                        //one header field can extend over one start line and multiple continuation lines
                        //a continuation line starts with at least 1 blank (' ') or tab
                        if (response[0] == ' ' || response[0] == '\t')
                        {
                            //continuation line found.
                            if (completeHeaderField == null)
                            {
                                callGetEmailWarning("Email header starts with continuation line", null);
                                //empty this message
                                while (readMultiLine(ref response))
                                {
                                }
                                System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                                return MimeEntityReturnCode.problem;
                            }
                            else
                            {
                                // append space, if needed, and continuation line
                                if (completeHeaderField[completeHeaderField.Length - 1] != ' ')
                                {
                                    //previous line did not end with a whitespace
                                    //need to replace CRLF with a ' '
                                    completeHeaderField += ' ' + response.TrimStart(WhiteSpaceChars);
                                }
                                else
                                {
                                    //previous line did end with a whitespace
                                    completeHeaderField += response.TrimStart(WhiteSpaceChars);
                                }
                            }

                        }
                        else
                        {
                            //a new header field line found
                            if (completeHeaderField == null)
                            {
                                //very first field, just copy it and then check for continuation lines
                                completeHeaderField = response;
                            }
                            else
                            {
                                //new header line found
                                ProcessHeaderField(message, completeHeaderField);

                                //save the beginning of the next line
                                completeHeaderField = response;
                            }
                        }
                    } //end while read header lines

                    //process body
                    //------------

                    MimeEntitySB.Length = 0; //empty StringBuilder. For speed reasons, reuse StringBuilder defined as member of class
                    string BoundaryDelimiterLineStart = null;
                    bool isBoundaryDefined = false;
                    if (message.ContentType.Boundary != null)
                    {
                        isBoundaryDefined = true;
                        BoundaryDelimiterLineStart = "--" + message.ContentType.Boundary;
                    }
                    //prepare return code for the case there is no boundary in the body
                    boundaryMimeReturnCode = MimeEntityReturnCode.bodyComplete;
                    //read body lines
                    while (readMultiLine(ref response))
                    {
                        //check if there is a boundary line from this entity itself in the body
                        if (isBoundaryDefined && response.TrimEnd(null) == BoundaryDelimiterLineStart)
                        {
                            //boundary line found.
                            //stop the processing here and start a delimited body processing
                            return ProcessDelimitedBody(message, BoundaryDelimiterLineStart, parentBoundaryStart, parentBoundaryEnd);
                        }

                        //check if there is a parent boundary in the body
                        if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, ref boundaryMimeReturnCode))
                        {
                            //a parent boundary is found. Decode the content of the body received so far, then end this MIME entity
                            //note that boundaryMimeReturnCode is set here, but used in the return statement
                            break;
                        }

                        //process next line
                        MimeEntitySB.Append(response + CRLF);
                    }

                    //a complete MIME body read
                    //convert received US ASCII characters to .NET string (Unicode)
                    string TransferEncodedMessage = MimeEntitySB.ToString();
                    bool isAttachmentSaved = false;
                    switch (message.ContentTransferEncoding)
                    {
                        case TransferEncoding.SevenBit:
                            //nothing to do
                            saveMessageBody(message, TransferEncodedMessage);
                            break;

                        case TransferEncoding.Base64:
                            //convert base 64 -> byte[]
                            byte[] bodyBytes = System.Convert.FromBase64String(TransferEncodedMessage);
                            message.ContentStream = new MemoryStream(bodyBytes, false);

                            if (message.MediaMainType == "text")
                            {
                                //convert byte[] -> string
                                message.Body = DecodeByteArryToString(bodyBytes, message.BodyEncoding);

                            }
                            else if (message.MediaMainType == "image" || message.MediaMainType == "application")
                            {
                                SaveAttachment(message);
                                isAttachmentSaved = true;
                            }
                            break;

                        case TransferEncoding.QuotedPrintable:
                            saveMessageBody(message, QuotedPrintable.Decode(TransferEncodedMessage));
                            break;

                        default:
                            saveMessageBody(message, TransferEncodedMessage);
                            break;
                            //no need to raise a warning here, the warning was done when analising the header
                    }

                    if (message.ContentDisposition != null&& message.ContentDisposition.DispositionType.ToLowerInvariant() == "attachment" && (! isAttachmentSaved))
                    {
                        SaveAttachment(message);
                        isAttachmentSaved = true;
                    }
                    return boundaryMimeReturnCode;
                }
Пример #11
0
        /// <summary>
        /// Check if the response line received is a parent boundary
        /// </summary>
        /// <param name="response">mail response line</param>
        /// <param name="parentBoundaryStart"> parent boundary start identifier</param>
        /// <param name="parentBoundaryEnd">parent boundary end identifier</param>
        /// <param name="boundaryMimeReturnCode">boundary MIME return code.</param>
        /// <returns>
        /// If parent boundary found then true or false
        /// </returns>
        private static bool ParentBoundaryFound(string response, string parentBoundaryStart, string parentBoundaryEnd, out MimeEntityReturnCode boundaryMimeReturnCode)
        {
            bool result = false;

            boundaryMimeReturnCode = MimeEntityReturnCode.undefined;
            if (null == response || 2 > response.Length || '-' != response[0] || '-' != response[1])
            {
                result = false;
            }

            else if (response == parentBoundaryStart)
            {
                boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryStartFound;
                result = true;
            }
            else if (response == parentBoundaryEnd)
            {
                boundaryMimeReturnCode = MimeEntityReturnCode.parentBoundaryEndFound;
                result = true;
            }

            return(result);
        }