Esempio n. 1
0
        internal static void MailSent(IAsyncResult result)
        {
            lock (lockObject)
            {
                MailTransmissionAsyncState asyncState       = (MailTransmissionAsyncState)result.AsyncState;
                MailTransmissionDelegate   asyncTransmitter = asyncState.dlgt;
                OutboundMailRecipient      recipient        = asyncState.recipient;
                try
                {
                    asyncTransmitter.EndInvoke(result);

                    try
                    {
                        recipient.Delete();
                        recipient.OutboundMail.IncrementSuccesses();
                    }
                    catch (Exception ex)
                    {
                        // whatever.. The mail is sent, but we couldn't mark it as such, probably a database failure.
                        asyncState.exception = new RemoveRecipientException("Couldn't remove mail recipient.", ex);
                        ExceptionMail.Send(asyncState.exception, true);
                    }
                }
                catch (ReportAndRetryRecipientException e)
                {
                    asyncState.exception = e;
                    Debug.WriteLine(e.ToString());
                    ExceptionMail.Send(e, true);
                }
                catch (RetryRecipientException e)
                {
                    // No action - handled in async delegate - retry this mail
                    asyncState.exception = e;
                }
                catch (Exception e)
                {
                    asyncState.exception = e;

                    try
                    {
                        recipient.Delete();
                        recipient.OutboundMail.IncrementFailures();

                        if (e is InvalidRecipientException)
                        {
                            if (recipient.Person != null && recipient.Person.EMailIsInvalid == false)
                            {
                                //Mark address as invalid.
                                recipient.Person.EMailIsInvalid = true;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Return this exception in asyncState since it is important to stop flooding.
                        asyncState.exception =
                            new RemoveRecipientException("Couldn't remove mail recipient after exception.", ex);
                        ExceptionMail.Send(asyncState.exception, true);  //Report the secondary exception
                    }


                    Debug.WriteLine(e.ToString());
                    ExceptionMail.Send(e, true);
                }

                asyncState.callbackCompleted = true;
            }
        }
Esempio n. 2
0
        internal static OutboundMailRecipient TransmitOneMail(OutboundMailRecipient recipient)
        {
            try
            {
                // If the mail address in illegal format, do not try to send anything:
                if (!Formatting.ValidateEmailFormat(recipient.EmailPerson.Email.Trim()))
                {
                    string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new InvalidRecipientException(msg, null);
                }

                // If the mail address is marked as unreachable, do not try to send anything
                if (recipient.Person != null && recipient.Person.MailUnreachable)
                {
                    string msg = "MailUnreachable email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new InvalidRecipientException(msg, null);
                }

                // If the mail address is marked as unreachable, do not try to send anything
                if (recipient.Person != null && recipient.Person.NeverMail)
                {
                    string msg = "NeverMail email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new IgnoreRecipientException(msg, null);
                }


                // Otherwise, let's start processing

                OutboundMail mail = recipient.OutboundMail;

                bool     limitToLatin1   = false;
                bool     limitToText     = false;
                Encoding currentEncoding = Encoding.UTF8;

                string email = recipient.EmailPerson.Email.ToLower();


                if (mail.MailType == 0 || mail.TemplateName.EndsWith("Plain"))
                {
                    limitToText = true;
                }

                // TEST: Does this user require the use of a text-only message (as opposed to multipart/alternative)?
                if (recipient.Person != null && recipient.Person.LimitMailToText)
                {
                    limitToText = true;
                }

                // This is supposedly not a problem anymore
                //if (email.EndsWith("@hotmail.com") || email.EndsWith("@msn.com"))
                //{
                //    limitToLatin1 = true;
                //}

                // TEST: Does this user require the limited use of the Latin-1 charset (as opposed to Unicode?)
                if (recipient.Person != null && recipient.Person.LimitMailToLatin1)
                {
                    limitToLatin1 = true;
                }

                // Capability tests end here

                if (limitToLatin1)
                {
                    currentEncoding = Encoding.GetEncoding("ISO-8859-1");
                }
                else
                {
                    currentEncoding = Encoding.UTF8;
                }

                QuotedPrintable qp = QuotedPrintableEncoder[currentEncoding];


                MailMessage message = new MailMessage();

                if (mail.AuthorType == MailAuthorType.Person)
                {
                    try
                    {
                        message.From = new MailAddress(mail.Author.PartyEmail,
                                                       qp.EncodeMailHeaderString(mail.Author.Name + " (" + mail.Organization.MailPrefixInherited +
                                                                                 ")"),
                                                       currentEncoding);

                        if (mail.Author.Identity == 1)
                        {
                            //TODO: Create alternative party mail optional data field, or organization chairman (based on roles) differently
                            // Ugly hack
                            message.From = new MailAddress("*****@*****.**",
                                                           qp.EncodeMailHeaderString(mail.Author.Name + " (" +
                                                                                     mail.Organization.MailPrefixInherited + ")"),
                                                           currentEncoding);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSenderException(
                                  "Invalid author address in MailProcessor.TransmitOneMail:" + (mail.AuthorPersonId) + ";" +
                                  mail.Author.PartyEmail, ex);
                    }
                }
                else
                {
                    try
                    {
                        FunctionalMail.AddressItem aItem =
                            mail.Organization.GetFunctionalMailAddressInh(mail.AuthorType);
                        message.From = new MailAddress(aItem.Email, qp.EncodeMailHeaderString(aItem.Name),
                                                       currentEncoding);
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSenderException(
                                  "Unknown MailAuthorType in MailProcessor.TransmitOneMail:" + ((int)mail.AuthorType), ex);
                    }
                }


                if (recipient.AsOfficer && recipient.Person != null)
                {
                    try
                    {
                        message.To.Add(new MailAddress(recipient.Person.PartyEmail,
                                                       qp.EncodeMailHeaderString(recipient.Person.Name + " (" +
                                                                                 mail.Organization.MailPrefixInherited + ")"),
                                                       currentEncoding));
                    }
                    catch (FormatException e)
                    {
                        string msg = "Invalid officer email address:\r\nperson [" + recipient.Person.Identity +
                                     "], mail [" +
                                     recipient.Person.PartyEmail + "]\r\nwill not send mail:" +
                                     recipient.OutboundMail.Title;
                        throw new InvalidRecipientException(msg, e);
                    }
                }
                else
                {
                    try
                    {
                        message.To.Add(new MailAddress(recipient.EmailPerson.Email,
                                                       qp.EncodeMailHeaderString(recipient.EmailPerson.Name),
                                                       currentEncoding));
                    }
                    catch (FormatException e)
                    {
                        string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                     "], mail [" +
                                     recipient.EmailPerson.Email + "]\r\nwill not send mail:" +
                                     recipient.OutboundMail.Title;
                        throw new InvalidRecipientException(msg, e);
                    }
                }

                string culture = mail.Organization.DefaultCountry.Culture;

                // UGLY UGLY UGLY HACK, NEEDS TO CHANGE ASAP:
                // We need to determine the culture of the recipient in order to use the right template. However, this is also dependent on the text body, which needs to be
                // in the same culture. At this point, we don't have the mail/recipient cultures in the schema. This would be the correct solution.

                // The INCORRECT but working solution is to do as we do here and check if a) it's a reporter and b) the reporter has International/English as a category. If so,
                // we change the culture to en-US. It's an ugly as all hell hack but it should work as a temporary stopgap.

                if (recipient.Reporter != null)
                {
                    MediaCategories categories = recipient.Reporter.MediaCategories;

                    foreach (MediaCategory category in categories)
                    {
                        if (category.Name == "International/English")
                        {
                            culture = Strings.InternationalCultureCode;
                            break;
                        }
                    }
                }

                if (limitToText)
                {
                    // if just text, then just add a plaintext body;
                    string text = "";

                    //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case..
                    lock (lockObject)
                    {
                        try
                        {
                            text = mail.RenderText(recipient.EmailPerson, culture);
                        }
                        catch (Exception ex)
                        {
                            throw new RemoveRecipientException(
                                      "TextRendering failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                      " will not retry.\n", ex);
                        }
                    }
                    message.BodyEncoding = currentEncoding;
                    message.Body         = text;
                }
                else
                {
                    // otherwise, add a multipart/alternative with text and HTML
                    string text = "";
                    string html = "";

                    //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case..
                    Exception ex = null;
                    lock (lockObject)
                    {
                        try
                        {
                            text = mail.RenderText(recipient.EmailPerson, culture);
                            html = mail.RenderHtml(recipient.EmailPerson, culture);
                        }
                        catch (Exception e)
                        {
                            ex = e;
                        }
                    }
                    if (text == "")
                    {
                        throw new RemoveRecipientException(
                                  "Rendering (text) failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                  " will not retry.\n", ex);
                    }
                    if (html == "" || ex != null)
                    {
                        throw new RemoveRecipientException(
                                  "Rendering (html) failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                  " will not retry.\n", ex);
                    }

                    ContentType textContentType = new ContentType(MediaTypeNames.Text.Plain);
                    textContentType.CharSet = currentEncoding.BodyName;

                    ContentType htmlContentType = new ContentType(MediaTypeNames.Text.Html);
                    htmlContentType.CharSet = currentEncoding.BodyName;

                    AlternateView textView = null;
                    AlternateView htmlView = null;


                    if (limitToLatin1)
                    {
                        textView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)),
                                                     textContentType);
                        htmlView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)),
                                                     htmlContentType);
                    }
                    else
                    {
                        textView = AlternateView.CreateAlternateViewFromString(text, textContentType);
                        htmlView = AlternateView.CreateAlternateViewFromString(html, htmlContentType);
                    }

                    // A f*****g stupid Mono bug forces us to transfer-encode in base64: it can't encode qp properly
                    // (the "=" is not encoded to "=3D")

                    htmlView.TransferEncoding = TransferEncoding.Base64;
                    textView.TransferEncoding = TransferEncoding.Base64;

                    // Add the views in increasing order of preference

                    message.AlternateViews.Add(textView);
                    message.AlternateViews.Add(htmlView);
                }

                if (mail.AuthorType == MailAuthorType.PirateWeb)
                {
                    message.Subject = mail.Title;
                }
                else if (mail.MailType == 0)
                {
                    message.Subject = mail.Organization.MailPrefixInherited + ": " + mail.Title;
                }
                else
                {
                    //Title is set up in template processing in OutboundMail rendering.
                    message.Subject = mail.Title;
                }

                message.SubjectEncoding = currentEncoding;

                string smtpServer = ConfigurationManager.AppSettings["SmtpServer"];

                if (Debugger.IsAttached)
                {
                    Debug.WriteLine("sending " + message.Subject + " to " + recipient.EmailPerson.Email);
                    Thread.Sleep(200);  //simulate delay
                }


                if (smtpServer.ToLower() != "none")
                {
                    if (smtpServer == null || smtpServer.Length < 2)
                    {
                        smtpServer = "localhost";
                    }

                    try
                    {
                        SmtpClient client = new SmtpClient(smtpServer, 25);
                        client.Send(message);
                    }
                    catch (SmtpException e)
                    {
                        if (e.ToString().StartsWith("System.Net.Mail.SmtpException: 4"))
                        {
                            // Temporary error (SMTP 4xx). Try again.

                            Thread.Sleep(2000);  // Allow 2 seconds pause to wait for smtp-server to become available
                            throw new ReportAndRetryRecipientException("Temporary smtp error, will retry.", e);
                        }

                        // Otherwise, bad recipient (assume so). Have the mail removed from the queue.

                        List <string> recipients = new List <string>();
                        foreach (MailAddress address in message.To)
                        {
                            recipients.Add(address.Address);
                        }

                        ExceptionMail.Send(
                            new ArgumentException(
                                "Bad Recipients when sending to " + recipient.EmailPerson.Email + ": " +
                                String.Join(", ", recipients.ToArray()), e));

                        if (mail.AuthorType == MailAuthorType.Person)
                        {
                            try
                            {
                                mail.Author.SendOfficerNotice(
                                    "Failed recipient(s): " + String.Join(", ", recipients.ToArray()),
                                    "Some recipients failed inexplicably in a mail from you.", 1);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Failed to SendOfficerNotice to :" + mail.AuthorPersonId, ex);
                            }
                        }
                    }
                }
                return(recipient); // To pass this object onto the we're-done callback
            }
            catch (InvalidRecipientException ex)
            {
                throw ex;
            }
            catch (RetryRecipientException ex)
            {
                Thread.Sleep(2000);
                // Allow 2 seconds pause to avoid flooding the errorlog too fast in case of a permanent failure
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }