andyedinborough / aenetmail

C# POP/IMAP Mail Client
370 stars 153 forks source link

Cannot get attachments from gmail #115

Closed tupieurods closed 11 years ago

tupieurods commented 11 years ago

Send mail from gmail to gmail. When i get message via AE.Net.Mail, there is no attacment in MailMessage.Attachments, it's in MailMessage.AlternateViews. In body property and not parsed.

Example of body property: Content-Type: image/jpeg; name="DSC_0081.jpg" Content-Disposition: attachment; filename="DSC_0081.jpg" Content-Transfer-Encoding: base64 X-Attachment-Id: 1421756057393299456-1

/9j/4RnuRXhpZgAATU0AKgAAAAgACgEPAAIAAAAOAAAAhgEQAAIAAAAGAAAAlAESAAMAAAABAAYA Long string in base64

P.S. Sorry for my bad english, it's not my native language.

537mfb commented 11 years ago

This happens more often than you may think. I even got an attachment in the main message body once. Wich is why i do a parsing job on the message on top of the already done parsing.

Something like this (not full code here but should give you an idea):

        foreach (Attachment a in msg.Attachments)
        {
            // Attachement is an Alternative/Complementing Message
            if ((a.ContentType.CompareTo("text/plain") == 0) && (a.Body.CompareTo(msg.Body) != 0) &&
                (String.IsNullOrEmpty(a.Filename))) // Text
                messages.AddRange(a.Body.Split(new[] {"\n", "\r\n"}, StringSplitOptions.None));
            else // HTML
                if ((a.ContentType.CompareTo("text/html") == 0) && (!hashtml || (htmlmsg.Contains("Content-Type"))))
                {
                    htmlmsg = a.Body;
                    if (htmlmsg.Contains("<"))
                        hashtml = true;
                }
            // Attachment is a file
            if (!String.IsNullOrEmpty(a.Filename))
            {
                if (!EmbededExists(a.Filename, embeded) && !a.Body.Contains("Content-Type"))
                    embeded.Add(new EmbededImage(a.ContentType, a.Filename, a.Body, a.Headers["Content-ID"].Value,
                                                 a.ContentTransferEncoding,
                                                 (EML > 0) ? "EML" + ((EML > 1) ? "_" + (EML - 1) : "") : ""));
            }
            else
            {
                if (a.ContentType.CompareTo("message/rfc822") == 0)
                {
                    EML++;
                    var attachedMessage = new MailMessage();
                    attachedMessage.Load(a.Body);
                    HandleMessage(attachedMessage, embeded, EML);
                }
                else
                {
                    if (a.Body.Contains("Content-Type") && a.Body.Contains("name"))
                    {
                        string[] tokens = a.Body.Split(';');
                        string[] data = a.Body.Split(new[] {"\r\n\r\n"},
                                                     StringSplitOptions.RemoveEmptyEntries);
                        string[] tokens2 = tokens[0].Split(':');
                        string contentType = tokens2[tokens2.Length - 1].Trim();
                        string extra = String.Empty;
                        for (int j = 1; j < tokens.Length; j += 2)
                        {
                            string[] encods = data[j - 1].Split(new[] {"\r\n", ";"},
                                                                StringSplitOptions.RemoveEmptyEntries);
                            var encod = new Dictionary<string, string>();
                            for (int k = encods.Length - 1; k > 0; k--)
                            {
                                string[] splited = encods[k].Split(new[] {":", "=\"", "\""},
                                                                   StringSplitOptions.RemoveEmptyEntries);
                                if (splited.Length == 2)
                                {
                                    if (splited[1].Contains("?Q?"))
                                        splited[1] = DecodeQuotedPrintables(splited[1], null) +
                                                     extra.Trim();
                                    encod.Add(splited[0].Trim(), splited[1].Trim().Replace("?", ""));
                                    extra = String.Empty;
                                }
                                else
                                    extra = splited[0].Contains("?Q?")
                                                ? DecodeQuotedPrintables(splited[0], null)
                                                : splited[0];
                            }
                            embeded.Add(new EmbededImage(contentType,
                                                         encod.ContainsKey("name")
                                                             ? encod["name"]
                                                             : (encod.ContainsKey("filename")
                                                                    ? encod["filename"]
                                                                    : ""),
                                                         data[j],
                                                         encod.ContainsKey("Content-ID")
                                                             ? encod["Content-ID"]
                                                             : "",
                                                         encod["Content-Transfer-Encoding"],
                                                         (EML > 0)
                                                             ? "EML" +
                                                               ((EML > 1) ? "_" + (EML - 1) : "")
                                                             : ""));
                        }
                    }
                }
            }
        }

This must be done for the main message, each alternative view and each attachment (in that order) - am not showing here a lot of my code regarding how i keep the data - just showing how to parse it.

Doing this fixes just about every mail i got so far - actually since my last update on this code, i haven't had a single one failling.

I also have my own code to get mail address and name when from is null and my own save attachement method.

Hope this helps some

537mfb commented 11 years ago

regarding my previous post: that code is imcomplete and far from optimal so take it with a pint of salt. It is provided 'AS IS' and with no garanties it will work on every mail you will receive. But it does improve my quota of success ten-fold.

I did so many fixes on it so far as new mails find errors that i'm pretty sure it could be optimised - but it works for me and i can't complain much on it's performance

c0d3l0g1c commented 11 years ago

Hi there! Can you please send me your full code posting for this? Need it quite urgently.

537mfb commented 11 years ago

That code is pretty much it - apply the same code to every alternateview just as i do here for every attachement same thing. I also apply the same code on the main message with a slight variant accounting it beeing the principal instance and not beeing a collection What else you need exactly? have you tried this code to see if it fits your needs?

andyedinborough commented 11 years ago

@537mfb, do you have an example message that this happens on?

537mfb commented 11 years ago

@andyedinborough plenty of them - unfortunatly non that i can share - there's a NDA in place at work and these are mails from customers we're working with. So far i was unable to recreate the issue using test mails created by myself - wich tells me the problem likely lies in our customers end. Mal-formed messages maybe? Can't really check on that since i don't really have access to a raw forn of the all message that the library gets to check it and check it against what the server has. Adding the full raw message somewhere would be great for debugging issues as this. Any plans on having something like that?

537mfb commented 11 years ago

@andyedinborough maybe @c0d3l0g1c can send you one of his?

I have noticed some pretty odd stuff using this library - There's no clear distinction between alternate views and attachments ai have gotten HTML and plain text messages aswell as files on both collections. Once i even got a pdf file in the main body message. This last one is what really made me think mal-formed messages. Maybe you follow RFC too strictly? Also some messages tend to throw out unhandled exceptions some times, but not always - wich is odd.

tupieurods commented 11 years ago

@andyedinborough, I can send my mail message, from first post of issue. May i send it to your email from profile?

andyedinborough commented 11 years ago

@537mfb That's really odd. :/ I haven't experienced that at all. Determining whether something is an attachment or alternate view is really simple--looks for content-disposition in the mime headers to be either "attachment" or "inline". It must be a parsing issue with the header.

Please, anytime you have an odd issue, and the contents of the message are not sensitive (or can be scrubbed), send me the message as an attachment to andy.edinborough@gmail.com.

537mfb commented 11 years ago

@andyedinborough - quite right - sould be a simple matter of verifying if it's 'text/plain' or 'text/html' or not. I can say that at least in most (if not all) that go that path, have a null content dispositon property (as well as other properties.- and the body contains the tags (Content-Type and Content-Disposition included) - so i assume something odd with the headers that your library doesn't account for? just guessing here. Most of our clients use company mail (@company.pt) so if only test with gmail and similar you might never see this. The more i see of this the more i belive it's a case of non-standard headers.

If i ever get one i can send i will but since i am now mostly in other projects given that my code above fixes about 99-100% of mails we get i shouldn't be able to provide one any time soon.

hope @tupieurods can hook you up with one

andyedinborough commented 11 years ago

I just found an issue with attachments. I'm in the process of expanding the testing that's done. A fix is forthcoming.

andyedinborough commented 11 years ago

Resolved with 05f4d8884f482abfb0918f2675363ee320ee04a7