Example #1
0
        /// <summary>
        /// Send an email message
        /// </summary>
        /// <param name="AEmail">on successful sending, the header is modified with the sent date</param>
        /// <returns>true if email was sent successfully</returns>
        public bool SendMessage(MailMessage AEmail)
        {
            if (AEmail.Headers.Get("Date-Sent") != null)
            {
                // don't send emails several times
                return false;
            }

            FailedRecipients.Clear();

            if (FSmtpClient.Host.EndsWith("example.org"))
            {
                TLogging.Log("Not sending the email, since the configuration is just with an example server: " + FSmtpClient.Host);
                TLogging.Log("You can configure the mail settings in the config file.");
                return false;
            }

            //Attempt to send the email
            try
            {
                AEmail.IsBodyHtml = AEmail.Body.ToLower().Contains("<html>");

                int AttemptCount = 3;

                while (AttemptCount > 0)
                {
                    AttemptCount--;
                    try
                    {
                        // for office365, this takes about 15 seconds
                        FSmtpClient.Send(AEmail);

                        AEmail.Headers.Add("Date-Sent", DateTime.Now.ToString());

                        return true;
                    }
                    catch (Exception e)
                    {
                        if (AttemptCount > 0)
                        {
                            Thread.Sleep(TimeSpan.FromMinutes(1));
                        }
                        else
                        {
                            throw e;
                        }
                    }
                }
            }
            catch (SmtpFailedRecipientsException frEx)  // If the SMTP server knows that the send failed because of failed recipients,
            {                                           // I can produce a list of failed recipient addresses, and return false.
                                                        // The caller can then retrieve the list and inform the user.
                TLogging.Log("SmtpEmail: Email to the following addresses did not succeed:");
                SmtpFailedRecipientException[] failureList = frEx.InnerExceptions;

                foreach (SmtpFailedRecipientException problem in failureList)
                {
                    TsmtpFailedRecipient FailureDetails = new TsmtpFailedRecipient();
                    FailureDetails.FailedAddress = problem.FailedRecipient;
                    FailureDetails.FailedMessage = problem.Message;
                    FailedRecipients.Add(FailureDetails);
                    TLogging.Log(problem.FailedRecipient + " : " + problem.Message);
                }

                return false;
            }
            catch (Exception ex)
            {
                // SSL authentication error: RemoteCertificateNotAvailable
                // see http://mono.1490590.n4.nabble.com/SSL-authentication-error-RemoteCertificateNotAvailable-RemoteCertificateChainErrors-td1755733.html
                // and http://www.mono-project.com/FAQ:_Security#Does_SSL_works_for_SMTP.2C_like_GMail_.3F
                // on Mono command prompt:
                //    mozroots --import --ask-remove --machine
                //    mozroots --import --ask-remove
                //    certmgr -ssl smtps://tim00.hostsharing.net:443

                TLogging.Log("There has been a problem sending the email");
                TLogging.Log("server: " + FSmtpClient.Host + ":" + FSmtpClient.Port.ToString());
                TLogging.Log(ex.ToString() + " " + ex.Message);
                TLogging.Log(ex.StackTrace);

                throw;
            }

            return false;
        }
Example #2
0
        /// <summary>
        /// Send an email message
        /// </summary>
        /// <param name="AEmail">on successful sending, the header is modified with the sent date</param>
        /// <returns>true if email was sent successfully</returns>
        public bool SendMessage(MailMessage AEmail)
        {
            if (AEmail.Headers.Get("Date-Sent") != null)
            {
                // don't send emails several times
                return(false);
            }

            FailedRecipients.Clear();

            if (FSmtpClient.Host.EndsWith("example.org"))
            {
                TLogging.Log("Not sending the email, since the configuration is just with an example server: " + FSmtpClient.Host);
                TLogging.Log("You can configure the mail settings in the config file.");
                return(false);
            }

            //Attempt to send the email
            try
            {
                AEmail.IsBodyHtml = AEmail.Body.ToLower().Contains("<html>");

                int AttemptCount = 3;

                while (AttemptCount > 0)
                {
                    AttemptCount--;
                    try
                    {
                        // for office365, this takes about 15 seconds
                        FSmtpClient.Send(AEmail);

                        AEmail.Headers.Add("Date-Sent", DateTime.Now.ToString());

                        return(true);
                    }
                    catch (Exception e)
                    {
                        if (AttemptCount > 0)
                        {
                            Thread.Sleep(TimeSpan.FromMinutes(1));
                        }
                        else
                        {
                            throw e;
                        }
                    }
                }
            }
            catch (SmtpFailedRecipientsException frEx)  // If the SMTP server knows that the send failed because of failed recipients,
            {                                           // I can produce a list of failed recipient addresses, and return false.
                                                        // The caller can then retrieve the list and inform the user.
                TLogging.Log("SmtpEmail: Email to the following addresses did not succeed:");
                SmtpFailedRecipientException[] failureList = frEx.InnerExceptions;

                foreach (SmtpFailedRecipientException problem in failureList)
                {
                    TsmtpFailedRecipient FailureDetails = new TsmtpFailedRecipient();
                    FailureDetails.FailedAddress = problem.FailedRecipient;
                    FailureDetails.FailedMessage = problem.Message;
                    FailedRecipients.Add(FailureDetails);
                    TLogging.Log(problem.FailedRecipient + " : " + problem.Message);
                }

                return(false);
            }
            catch (Exception ex)
            {
                // SSL authentication error: RemoteCertificateNotAvailable
                // see http://mono.1490590.n4.nabble.com/SSL-authentication-error-RemoteCertificateNotAvailable-RemoteCertificateChainErrors-td1755733.html
                // and http://www.mono-project.com/FAQ:_Security#Does_SSL_works_for_SMTP.2C_like_GMail_.3F
                // on Mono command prompt:
                //    mozroots --import --ask-remove --machine
                //    mozroots --import --ask-remove
                //    certmgr -ssl smtps://tim00.hostsharing.net:443

                TLogging.Log("There has been a problem sending the email");
                TLogging.Log("server: " + FSmtpClient.Host + ":" + FSmtpClient.Port.ToString());
                TLogging.Log(ex.ToString() + " " + ex.Message);
                TLogging.Log(ex.StackTrace);

                throw;
            }

            return(false);
        }
Example #3
0
        /// <summary>
        /// Send an email message
        /// </summary>
        /// <param name="AEmail">On successful sending, the header is modified with the sent date.</param>
        /// <returns>True if email was sent successfully.</returns>
        public bool SendMessage(MimeMessage AEmail)
        {
            if (AEmail.Headers["Date-Sent"] != null)
            {
                // don't send emails several times
                return(false);
            }

            FFailedRecipients.Clear();

            //Attempt to send the email
            // FIXME!! Some SMTP servers have a message rate limit, so if a message is rejected because we have exceeded the maximum number
            // of messages per minute, we need to wait and retry (https://tracker.openpetra.org/view.php?id=3179). Unfortunately the solution
            // here doesn't check what _kind_ of error occurred. So for a permanent error like incorrect credentials... for 100 HOSAs... it
            // will happily retry one after another for 5 hours before telling the user they all failed.
            //
            // You can catch the SmtpClient exceptions and check the StatusCode enum to get a better idea of the problem. The numeric values of
            // the enum match SMTP error codes as shown below. Codes in the 400 range are generally 'temporary' failures while codes in the 500
            // range are usually'permanent'. It's more complicated than it should be because:
            //    i) If a MimeMessage has one To: address, failure is returned in a SmtpFailedRecipientException.
            //       If a MimeMessage has one To: address and one CC: address, failure is returned in a SmtpFailedRecipientsException (note the plural).
            //       This contains an InnerExceptions property containing the individual SmtpFailedRecipientExceptions which Microsoft say is "not
            //       intended to be used directly from your code".
            //   ii) There are different kinds of "permanent" errors and SMTP servers aren't consistent about how they report things. For example,
            //       for an authentication error, mail.smtp2go.com returns "Mailbox Unavailable. The server response was: Relay denied for unauthenticated sender".
            //       You need to check the exception Message text to see whether the error is to do with the recipient mailbox (so mail to a
            //       different recipient may work) or the sender account (so nothing will work and you may as well abort the whole process now).
            //
            // SmtpStatusCode Enumeration with numeric values:
            //    -1      GeneralFailure
            //   211     SystemStatus
            //   214     HelpMessage
            //   220     ServiceReady
            //   221     ServiceClosingTransmissionChannel
            //   250     Ok
            //   251     UserNotLocalWillForward
            //   252     CannotVerifyUserWillAttemptDelivery
            //   354     StartMailInput
            //   421     ServiceNotAvailable
            //   450     MailboxBusy
            //   451     LocalErrorInProcessing
            //   452     InsufficientStorage
            //   454     ClientNotPermitted
            //   500     CommandUnrecognized
            //   501     SyntaxError
            //   502     CommandNotImplemented
            //   503     BadCommandSequence
            //   504     CommandParameterNotImplemented
            //   530     MustIssueStartTlsFirst
            //   550     MailboxUnavailable
            //   551     UserNotLocalTryAlternatePath
            //   552     ExceededStorageAllocation
            //   553     MailboxNameNotAllowed
            //   554     TransactionFailed

            try
            {
                int AttemptCount = 3;

                while (AttemptCount > 0)
                {
                    AttemptCount--;
                    try
                    {
                        TLogging.LogAtLevel(1, "Trying to send E-Mail to " +
                                            AEmail.To.ToString() + " from " + AEmail.From.ToString());

                        if (!AEmail.From.ToString().Substring(AEmail.From.ToString().IndexOf("@")).Contains("."))
                        {
                            // invalid Email domain, eg. local
                            return(false);
                        }

                        // for office365, this takes about 15 seconds
                        FSmtpClient.Send(AEmail);

                        AEmail.Headers.Add("Date-Sent", DateTime.Now.ToString());

                        TLogging.LogAtLevel(1, "E-Mail was sent successfully");

                        return(true);
                    }
                    catch (Exception ex)
                    {
                        if (AttemptCount > 0)
                        {
                            Thread.Sleep(TimeSpan.FromMinutes(1));
                        }
                        else
                        {
                            TLogging.LogException(ex, Utilities.GetMethodSignature());
                            throw;
                        }
                    }
                }
            }
            catch (SmtpCommandException frEx)  // If the SMTP server knows that the send failed because of failed recipients,
            {                                  // I can produce a list of failed recipient addresses, and return false.
                                               // The caller can then retrieve the list and inform the user.
                TLogging.Log("SmtpEmail: Email to the following addresses did not succeed:");

                if (frEx.ErrorCode == SmtpErrorCode.RecipientNotAccepted)
                {
                    TsmtpFailedRecipient FailureDetails = new TsmtpFailedRecipient();
                    FailureDetails.FailedAddress = frEx.Mailbox.ToString();
                    FailureDetails.FailedMessage = "Recipient not accepted";
                    FFailedRecipients.Add(FailureDetails);
                    TLogging.Log(FailureDetails.FailedAddress + " : " + FailureDetails.FailedMessage);
                }

                return(false);
            }
            catch (Exception ex)
            {
                // SSL authentication error: RemoteCertificateNotAvailable
                // see http://mono.1490590.n4.nabble.com/SSL-authentication-error-RemoteCertificateNotAvailable-RemoteCertificateChainErrors-td1755733.html
                // and http://www.mono-project.com/FAQ:_Security#Does_SSL_works_for_SMTP.2C_like_GMail_.3F
                // on Mono command prompt:
                //    mozroots --import --ask-remove --machine
                //    mozroots --import --ask-remove
                //    certmgr -ssl smtps://tim00.hostsharing.net:443

                TLogging.Log("There has been a problem sending the email");
                TLogging.Log(ex.ToString() + " " + ex.Message);
                TLogging.Log(ex.StackTrace);

                throw;
            }

            return(false);
        }