Example #1
0
        /// <summary>
        /// Creates a mail info object based on information on a page.
        /// </summary>
        /// <returns></returns>
        public virtual MailInformation GetMailInformation(PageData mailPage)
        {
            // Get Meta Information
            MailInformation mailInfo = GetMailMetaData(mailPage);

            // Get the two body versions
            string mailBody = GetPageHtml(mailPage);

            string hostUrl = GetSiteUrl(mailPage);

            mailInfo.BodyHtml = RewriteUrls(mailBody, hostUrl);

            mailInfo.BodyText = QuickCleanMailText(GetPageText(mailPage));

            // Let page add custom properties
            IPopulateCustomProperties customPropertiesProvider = mailPage as IPopulateCustomProperties;

            if (customPropertiesProvider != null)
            {
                // Let page populate the custom properties collection
                customPropertiesProvider.AddCustomProperties(mailInfo.CustomProperties);
            }

            return(mailInfo);
        }
Example #2
0
        /// <summary>
        /// Creates the mail info object with only meta information like subject
        /// sender etc. Does not add mail content to the object.
        /// </summary>
        public virtual MailInformation GetMailMetaData(PageData mailPage)
        {
            // Get content from page
            MailInformation mailInfo = new MailInformation();

            mailInfo.PageLink = mailPage.PageLink;
            mailInfo.Subject  = GetMailSubject(mailPage);
            if (mailPage["BaseUrl"] != null)
            {
                mailInfo.BaseUrl = mailPage["BaseUrl"].ToString();
            }
            else
            {
                mailInfo.BaseUrl = GetSiteUrl(mailPage);
            }

            // The pagename can be used for other things later on
            mailInfo.PageName = mailInfo.PageName;

            // Sender address
            mailInfo.From = GetMailSender(mailPage);

            // Campaign data
            mailInfo.Utm.Campaign = GetCampaign(mailPage);

            return(mailInfo);
        }
        /// <summary>
        /// Populates needed mail information before sending. Will also check
        /// for Mailgun specific properties
        /// </summary>
        /// <remarks>
        /// Note! Mailgun validate campaign codes, and if the campaign does
        /// not exist, it will be ignored (the email will still be sent)
        /// Note! Tags are limited to a count of 200
        /// </remarks>
        /// <param name="mailPage"></param>
        /// <returns></returns>
        public override MailInformation GetMailInformation(PageData mailPage)
        {
            MailInformation mailInformation = base.GetMailInformation(mailPage);

            IPopulateCustomProperties customPropertiesProvider = mailPage as IPopulateCustomProperties;

            if (customPropertiesProvider == null)
            {
                // The base class will add custom properties if the page type
                // implements that - if NOT, we'll try to add them ourselves
                // by looking for special property names relevant to Mailgun
                var campaign = mailPage[MAILGUN_CAMPAIGN_PROPERTYNAME];
                if (campaign != null)
                {
                    mailInformation.Utm.Campaign = campaign.ToString();
                }

                // Since the Utm Campaign can be set independently, we check if it
                // is set, and use it as a Mailgun campaign too
                if (string.IsNullOrEmpty(mailInformation.Utm.Campaign) == false)
                {
                    mailInformation.CustomProperties.Add("o:campaign", mailInformation.Utm.Campaign);
                }


                if (mailPage[MAILGUN_TAG_PROPERTYNAME] != null)
                {
                    mailInformation.CustomProperties.Add("o:tag", mailPage[MAILGUN_TAG_PROPERTYNAME]);
                }
            }
            return(mailInformation);
        }
Example #4
0
        protected MailInformation GetMailInformation(MailSenderBase sender, ContentReference pageRef, string from, string subject)
        {
            // Get content to send
            MailInformation mailInfo = sender.GetMailInformation(pageRef as PageReference);

            if (!string.IsNullOrEmpty(subject))
            {
                mailInfo.Subject = subject; // Can be something other than the pagename
            }
            mailInfo.From = from;
            return(mailInfo);
        }
Example #5
0
        public MailInformation GetHtmlReport(string from, string subject, bool ShowSuccessAddresses)
        {
            if (from == null)
            {
                throw new ArgumentNullException("from", "From email address cannot be null");
            }

            MailInformation mailInfo = new MailInformation();

            mailInfo.Subject = subject;
            mailInfo.From    = from;

            System.Text.StringBuilder reportMailBody = new System.Text.StringBuilder();
            reportMailBody.AppendLine("<div id=\"MailReport\">");

            // Start send
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Started send:</span> <span class=\"onelinesectionvalue\">{0}</span></span></div>", this.SendStart.ToString());

            // Start send
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">End send:</span> <span class=\"onelinesectionvalue\">{0}</span></div>", this.SendStop.ToString());

            // Duration
            TimeSpan duration = TimeSpan.FromMilliseconds((double)this.TotalDuration);

            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Duration:</span> <span class=\"onelinesectionvalue\">{0}hr {1}min {2}sec</span></div>", duration.Hours.ToString(), duration.Minutes.ToString(), duration.Seconds.ToString());

            // Number of emails sent
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Number of emails sent:</span> <span class=\"onelinesectionvalue\">{0}</span></div>", this.NumberOfEmailsSent.ToString());

            // Exceptions first
            if (ErrorMessages.Count > 0)
            {
                AppendMultiLineSectionAsHtml("Exceptions", ErrorMessages, reportMailBody);
            }

            // Warnings next
            if (WarningMessages.Count > 0)
            {
                AppendMultiLineSectionAsHtml("Warnings", WarningMessages, reportMailBody);
            }

            // Successfull HTML Text Recipients
            if (ShowSuccessAddresses == true)
            {
                AppendMultiLineSectionAsHtml("Successfull HTML Format Recipients", SuccessMessages, reportMailBody);
            }

            reportMailBody.AppendLine("</div>");
            mailInfo.BodyHtml = reportMailBody.ToString();

            return(mailInfo);
        }
        /// <summary>
        /// Sends the mail batch using the SendGrid API
        /// </summary>
        /// <param name="mail">The mail.</param>
        /// <param name="recipients">The recipients.</param>
        /// <param name="onlyTestDontSendMail">if set to <c>true</c> [only test dont send mail].</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool SendMailBatch(MailInformation mail, IEnumerable<JobWorkItem> recipients, bool onlyTestDontSendMail)
        {
            var settings = GetSettings();

            if (recipients == null || recipients.Any() == false)
                throw new ArgumentException("No workitems", "recipients");

            if (recipients.Count() > 1000)
                throw new ArgumentOutOfRangeException("recipients", "SendGrid supports maximum 1000 recipients per batch send.");

            var msg = new SendGridMessage();
            msg.From = new MailAddress(mail.From);
            msg.Subject = mail.Subject;
            msg.Html = mail.BodyHtml;
            msg.Text = mail.BodyText;

            // Add recipinets to header, to hide other recipients in to field.
            List<string> addresses = recipients.Select(r => r.EmailAddress).ToList();
            msg.Header.SetTo(addresses);
            msg.AddSubstitution("%recipient%", addresses);
            // To send message we need to have a to address, set that to from
            msg.To = new MailAddress[] { msg.From };

            if (mail.EnableTracking)
            {
                // true indicates that links in plain text portions of the email
                // should also be overwritten for link tracking purposes.
                msg.EnableClickTracking(true);
                msg.EnableOpenTracking();
            }

            if(mail.CustomProperties.ContainsKey("SendGridCategory"))
            {
                string category = mail.CustomProperties["SendGridCategory"] as string;
                if (string.IsNullOrEmpty(category) == false)
                    msg.SetCategory(category);
            }

            var credentials = new NetworkCredential(settings.Username, settings.Password);

            // Create an Web transport for sending email.
            var transportWeb = new Web(credentials);

            transportWeb.Deliver(msg);

            return true;
        }
Example #7
0
        /// <summary>
        /// Send mail to mailreceivers
        /// </summary>
        /// <param name="subject">subject for mail</param>
        /// <param name="pageRef">reference to mailpage</param>
        /// <param name="from">from-address for mail</param>
        /// <param name="onlyTestDontSendMail">No mails are sent, generating report for user</param>
        /// <param name="job">The job to send as newsletter</param>
        /// <returns></returns>
        public SendMailLog SendNewsletter(string subject, string from, ContentReference pageRef, JobWorkItems workItems, bool onlyTestDontSendMail)
        {
            // Construct correct sender object based on config setting
            MailSenderBase sender = GetMailSender();

            // Construct mail object with default values and content
            MailInformation mailInfo = GetMailInformation(sender, pageRef, from, subject);

            // Send it
            SendMailLog log;

            log = sender.SendEmail(mailInfo, workItems, onlyTestDontSendMail);

            // Add additional information to the log
            log.Subject = subject;

            return(log);
        }
        /// <summary>
        /// Send mail to mailreceivers using Mailgun REST API
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recepients">receivers</param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A html formatted report of the send process</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode)
        {
            _log.Debug("Starting Mailgun Send");

            // Inline all css
            InlineResult cssInline = PreMailer.Net.PreMailer.MoveCssInline(mailInfo.BodyHtml);

            mailInfo.BodyHtml = cssInline.Html;

            // Base will send
            SendMailLog log = base.SendEmail(mailInfo, recepients, testMode);

            // Log any messages, debug is only detected
            // if we have an HttpContext.
            if (IsInDebugMode())
            {
                log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers.");
                log.WarningMessages.AddRange(cssInline.Warnings.ToArray());
            }

            _log.Debug("Ending Mailgun Send");
            // return report
            return(log);
        }
Example #9
0
        public override bool SendMailBatch(MailInformation mail, IEnumerable<JobWorkItem> recipients, bool onlyTestDontSendMail)
        {
            MailgunSettings settings = GetSettings();

            // ReSharper disable PossibleMultipleEnumeration
            if(recipients == null || recipients.Count() == 0)
                throw new ArgumentException("No workitems", "recipients");

            if(recipients.Count() > 1000)
                throw new ArgumentOutOfRangeException("recipients", "Mailgun supports maximum 1000 recipients per batch send.");

            RestClient client = new RestClient();
            client.BaseUrl = new Uri("https://api.mailgun.net/v2");
            client.Authenticator = new HttpBasicAuthenticator("api", settings.ApiKey);

            if(string.IsNullOrEmpty(settings.ProxyAddress) == false)
            {
                client.Proxy = new WebProxy(settings.ProxyAddress, settings.ProxyPort); // Makes it easy to debug as Fiddler will show us the requests
            }

            RestRequest request = new RestRequest();
            request.AlwaysMultipartFormData = true;
            request.AddParameter("domain", settings.Domain, ParameterType.UrlSegment);
            request.Resource = "{domain}/messages";
            request.AddParameter("from", mail.From);
            request.AddParameter("subject", mail.Subject);
            request.AddParameter("text", mail.BodyText);
            request.AddParameter("html", mail.BodyHtml);

            if(mail.EnableTracking)
            {
                request.AddParameter("o:tracking", mail.EnableTracking);
                request.AddParameter("o:tracking-clicks", mail.EnableTracking);
                request.AddParameter("o:tracking-opens", mail.EnableTracking);
            }

            foreach (KeyValuePair<string, object> customProperty in mail.CustomProperties)
            {
                request.AddParameter(customProperty.Key, customProperty.Value.ToString());
            }

            // Add custom data about job
            if (mail.CustomProperties.ContainsKey("v:newsletter-data") == false)
            {
                request.AddParameter("v:newsletter-data",
                                     string.Format("{{\"id\": \"{0}\", \"page\": \"{1}\" }}",
                                                    recipients.First().JobId, mail.PageLink.ID));
            }

            // Add all recipients
            StringBuilder recipVariables = new StringBuilder();
            bool first = true;
            foreach (JobWorkItem recipient in recipients)
            {
                request.AddParameter("to", recipient.EmailAddress);

                if (first == false)
                {
                    recipVariables.Append(",");
                }
                first = false;
                recipVariables.AppendFormat("\"{0}\" : {{\"id\": \"{1}\" }}", recipient.EmailAddress, recipient.GetHashCode());
            }
            request.AddParameter("recipient-variables", "{" + recipVariables.ToString() + "}");

            //if(onlyTestDontSendMail)
            //{
            //    request.AddParameter("o:testmode", true);
            //}

            request.Method = Method.POST;
            var response = client.Execute(request);

            Dictionary<string, string> resultParams = null;
            try
            {
                resultParams = new JsonDeserializer().Deserialize<Dictionary<string, string>>(response);
            }
            catch (Exception e)
            {
                _log.Warning("Unable to parse Mailgun response.", e);
            }

            if(response.StatusCode == HttpStatusCode.OK)
            {
                _log.Debug("Mailgun responded with: {0} - {1}", response.StatusCode, response.StatusDescription);
                if(string.IsNullOrEmpty(response.ErrorMessage) == false)
                {
                    _log.Error("Response Error: {0}", response.ErrorMessage);
                }
                _log.Debug(response.Content);

                // json looks like:
                //{
                //  "message": "Queued. Thank you.",
                //  "id": "<*****@*****.**>"
                //}

                // Update all recipients with information
                if(resultParams != null)
                {
                    string info = resultParams["id"];
                    foreach (JobWorkItem recipient in recipients)
                    {
                        recipient.Info = info;
                    }

                }
            }
            else
            {
                _log.Debug("Mailgun responded with: {0} - {1}", response.StatusCode, response.StatusDescription);
                string errorMessage = response.StatusDescription;
                if(resultParams != null)
                    errorMessage = resultParams["message"];

                if (string.IsNullOrEmpty(response.ErrorMessage) == false)
                {
                    _log.Error("Response Error: {0}", response.ErrorMessage);
                }
                _log.Debug(response.Content);

                throw new HttpException((int)response.StatusCode, errorMessage);
            }

            return true;
            // ReSharper restore PossibleMultipleEnumeration
        }
Example #10
0
 public abstract bool SendMailBatch(MailInformation mail, IEnumerable <JobWorkItem> recipients, bool onlyTestDontSendMail);
Example #11
0
        /// <summary>
        /// Send mail to mailreceivers using System.Net.Mail
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recepients">receivers</param>
        /// <param name="from">from-address for mail</param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A html formatted report of the send process</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode)
        {
            _log.Debug("Starting Send");
            // for logging
            SendMailLog log = new SendMailLog();

            log.SendStart = DateTime.Now;

            // HttpContext.Current.Server.ScriptTimeout = 7200;

            // Need someone to send to
            if (recepients.Items.Count == 0)
            {
                _log.Error("Trying to send newsletter with an empty JobWorkCollection. Please check the collection before attemting to send mail.");
                throw new ArgumentNullException("recepients", "Recipient collection is empty, there is no recipients to send to.");
            }

            // And, we need a sender address
            if (string.IsNullOrEmpty(mailInfo.From))
            {
                _log.Error("Missing from address. SMTP servers do not allow sending without a sender.");
                throw new ArgumentNullException("mailInfo", "Missing from address. SMTP servers do not allow sending without a sender.");
            }

            // Loop through receivers collection, send email for each
            foreach (JobWorkItem recipient in recepients)
            {
                _log.Debug(string.Format("Job {0}, Email: {1}, Status: {2}",
                                         recipient.JobId.ToString(), recipient.EmailAddress, recipient.Status.ToString()));

                MailMessage mail = new MailMessage(mailInfo.From, recipient.EmailAddress);
                mail.Subject = mailInfo.Subject;

                mail.Body       = mailInfo.BodyHtml;
                mail.IsBodyHtml = true;

                try
                {
                    if (SendMail(mail, testMode))
                    {
                        log.SuccessMessages.Add(recipient.EmailAddress);

                        // Update status and save it
                        recipient.Status = JobWorkStatus.Complete;
                        // Only save if real work item (could be a test item)
                        if (recipient.JobId > 0)
                        {
                            recipient.Save();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(string.Format("Error sending to email: {0}", recipient.EmailAddress), ex);
                    string exceptionMsg = string.Format("Email: {0}\r\nException: {1}\r\n\r\n", recipient.EmailAddress, ex.Message);
                    log.ErrorMessages.Add(exceptionMsg);

                    // Update work item
                    recipient.Status = JobWorkStatus.Failed;
                    if (exceptionMsg.Length >= 2000)
                    {
                        exceptionMsg = exceptionMsg.Substring(0, 1999);
                    }
                    recipient.Info = exceptionMsg;
                    if (recipient.JobId > 0)
                    {
                        recipient.Save();
                    }
                }
            }

            // Finished
            log.SendStop = DateTime.Now;

            _log.Debug("Ending Send");
            // return report
            return(log);
        }
Example #12
0
 /// <summary>
 /// Send mail to mailreceivers using System.Web.Mail
 /// </summary>
 /// <param name="mailInfo">A MailInformation object with the content to send</param>
 /// <param name="recepients">receivers</param>
 /// <param name="testMode">No mails are sent, generating report for user</param>
 /// <returns>A report of the send process</returns>
 public abstract SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode);
Example #13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recepients">receivers</param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A html formatted report of the send process</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode)
        {
            _log.Debug("Starting Send");
            // for logging
            SendMailLog log = new SendMailLog();

            // Need someone to send to
            if (recepients.Items.Count == 0)
            {
                _log.Error("Trying to send newsletter with an empty JobWorkCollection. Please check the collection before attemting to send mail.");
                throw new ArgumentNullException("recepients", "Recipient collection is empty, there is no recipients to send to.");
            }

            // And, we need a sender address
            if (string.IsNullOrEmpty(mailInfo.From))
            {
                _log.Error("Missing from address.");
                throw new ArgumentNullException("mailInfo", "Missing from address.");
            }

            // Inline all css
            PreMailer.Net.PreMailer preMailer = new PreMailer.Net.PreMailer(mailInfo.BodyHtml);
            if (mailInfo.Utm.HasValidUtmCode)
            {
                preMailer.AddAnalyticsTags(mailInfo.Utm.Source, mailInfo.Utm.Medium, mailInfo.Utm.Campaign,
                                           mailInfo.Utm.Content);
            }
            InlineResult cssInline = preMailer.MoveCssInline();

            mailInfo.BodyHtml = cssInline.Html;

            // Log any messages, debug is only detected
            // if we have an HttpContext.
            if (IsInDebugMode())
            {
                log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers.");
                log.WarningMessages.AddRange(cssInline.Warnings.ToArray());
            }

            // Loop through receivers collection, add to collection and send
            // one email per batch size.
            int batchRun  = 0;
            int batchSize = GetBatchSize();

            do
            {
                IEnumerable <JobWorkItem> workItems = recepients.Skip(batchRun * batchSize).Take(batchSize);
                int numberofItemsToSend             = workItems.Count();
                if (numberofItemsToSend == 0)
                {
                    break;
                }
                batchRun++;

                try
                {
                    if (SendMailBatch(mailInfo, workItems, testMode))
                    {
                        // Mark each item as sent
                        foreach (JobWorkItem workItem in workItems)
                        {
                            log.SuccessMessages.Add(workItem.EmailAddress);
                            // Update status and save it
                            workItem.Status = JobWorkStatus.Complete;
                            // Only save if real work item (could be a test item)
                            if (workItem.JobId > 0)
                            {
                                workItem.Save();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(string.Format("Error sending batch (to {0} recipients).", recepients.Count()), ex);
                    string exceptionMsg = ex.Message;
                    log.ErrorMessages.Add(exceptionMsg);

                    // Update work item
                    foreach (JobWorkItem workItem in workItems)
                    {
                        workItem.Status = JobWorkStatus.Failed;
                        if (exceptionMsg.Length >= 2000)
                        {
                            exceptionMsg = exceptionMsg.Substring(0, 1999);
                        }
                        workItem.Info = exceptionMsg;
                        if (workItem.JobId > 0)
                        {
                            workItem.Save();
                        }
                    }

                    // can't continue
                    break;
                }
            } while (true);

            // Finished
            log.SendStop = DateTime.Now;

            _log.Debug("Ending Send");
            // return report
            return(log);
        }
        /// <summary>
        /// Send mail to mailreceivers using System.Web.Mail
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recipients"></param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A SendMailLog object with information about the status of the job.</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recipients, bool testMode)
        {
            _log.Debug("900.10.11.1 Starting Send");
            // for logging
            SendMailLog log = new SendMailLog();

            log.StartJob();
            // Recipients util
            RecipientsUtility recipUtil = new RecipientsUtility();

            // We try to verify as many settings, variables etc. before
            // starting the sending loop, as we don't want to generate
            // lots of exceptions in a loop.

            // Need someone to send to
            if (recipients.Items.Count == 0)
            {
                _log.Error("900.10.11.2 Trying to send mail with an empty JobWorkItems collection. Please check the collection before attemting to send mail.");
                throw new ArgumentNullException("Recipient collection is empty, there is no recipients to send to.", "recepients");
            }

            // And, we need a sender address
            if (mailInfo.From == null || mailInfo.From == string.Empty)
            {
                _log.Error("900.10.11.3 Missing from address. SMTP servers do not allow sending without a sender.");
                throw new ArgumentNullException("Missing from address. SMTP servers do not allow sending without a sender.", "mailInfo.From");
            }

            // Load the license. This needs to be in the
            EmailMessage.LoadLicenseString(GetLicenseFileContents());

            // We'll reuse the mail object, so we create it outside of the loop
            EmailMessage mail = CreateMessage(mailInfo);

            // Set port and authentication details if found
            InitializeMailSettings(ref mail);

            // Send a warm-up message outside the loop. This
            // will help us catch any misconfigurations and other
            // things that prevents us from sending emails. By
            // doing this outside the loop, we won't kill the
            // application or log with uneccesary error messages.
            // TODO: Implement this

            // Loop through receivers collection, send email for each
            foreach (JobWorkItem workItem in recipients)
            {
                _log.Debug(string.Format("900.10.11.5 Job {0}, Email: {1}, Status: {2}",
                                         workItem.JobId.ToString(), workItem.EmailAddress, workItem.Status.ToString()));

                // Only attempt sending those that have been stamped as ready for sending
                // unless we're in a test case.
                if (workItem.Status == JobWorkStatus.Sending || testMode == true)
                {
                    try
                    {
                        // At this point we assume the address is formatted correctly
                        // and checked, but aspNetEmail checks the to address on set, may fail
                        mail.To = workItem.EmailAddress;

                        // Perform actual send, if testmail, then this will
                        // return false. We should not update the status on
                        // test sends
                        bool result = SendMail(mail, testMode);
                        if (result == true)
                        {
                            log.SuccessMessages.Add(workItem.EmailAddress);

                            // Update status and save it
                            // TODO: Improve performance by doing this in batch
                            workItem.Status = JobWorkStatus.Complete;
                            // Only save if real work item (could be a test item)
                            if (workItem.JobId > 0)
                            {
                                workItem.Save();
                            }
                        }
                        // else
                        // Could not send, it has been disabled by
                        // settings or parameters
                    }
                    catch (Exception ex)
                    {
                        _log.Error(string.Format("900.10.11.6 Error sending to email: {0}", workItem.EmailAddress), ex);
                        string exceptionMsg = string.Format("Email: {0}\r\nException: {1}\r\n\r\n", workItem.EmailAddress, ex.Message);
                        log.ErrorMessages.Add(exceptionMsg);

                        // Update work item
                        workItem.Status = JobWorkStatus.Failed;
                        if (exceptionMsg.Length >= 2000)
                        {
                            exceptionMsg = exceptionMsg.Substring(0, 1999);
                        }
                        workItem.Info = exceptionMsg;
                        if (workItem.JobId > 0)
                        {
                            workItem.Save();
                        }
                    }
                }
                else
                {
                    _log.Debug(string.Format("900.10.11.7 Skipping Recipient, wrong status. Job {0}, Email: {1}, Status: {2}",
                                             workItem.JobId.ToString(), workItem.EmailAddress, workItem.Status.ToString()));
                }
            }

            // Finished
            log.StopJob();

            // Warn user if logging is enabled
            if (Configuration.NewsLetterConfiguration.ExtendedLogFile != null)
            {
                log.WarningMessages.Add("Logging has been enabled. Only use during troubleshooting.");
            }

            _log.Debug("900.10.11.8 Ending Send");
            // return report
            return(log);
        }
Example #15
0
        /// <summary>
        /// Creates the mail info object with only meta information like subject
        /// sender etc. Does not add mail content to the object.
        /// </summary>
        public virtual MailInformation GetMailMetaData(PageData mailPage)
        {
            // Get content from page
            MailInformation mailInfo = new MailInformation();

            mailInfo.PageLink = mailPage.PageLink;
            mailInfo.Subject = GetMailSubject(mailPage);
            if (mailPage["BaseUrl"] != null)
                mailInfo.BaseUrl = mailPage["BaseUrl"].ToString();
            else
                mailInfo.BaseUrl = GetSiteUrl(mailPage);

            // The pagename can be used for other things later on
            mailInfo.PageName = mailInfo.PageName;

            // Sender address
            mailInfo.From = GetMailSender(mailPage);

            // Campaign data
            mailInfo.Utm.Campaign = GetCampaign(mailPage);

            return mailInfo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recepients">receivers</param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A html formatted report of the send process</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode)
        {
            _log.Debug("Starting Send");
            // for logging
            SendMailLog log = new SendMailLog();

            // Need someone to send to
            if (recepients.Items.Count == 0)
            {
                _log.Error("Trying to send newsletter with an empty JobWorkCollection. Please check the collection before attemting to send mail.");
                throw new ArgumentNullException("recepients", "Recipient collection is empty, there is no recipients to send to.");
            }

            // And, we need a sender address
            if (string.IsNullOrEmpty(mailInfo.From))
            {
                _log.Error("Missing from address.");
                throw new ArgumentNullException("mailInfo", "Missing from address.");
            }

            // Inline all css
            PreMailer.Net.PreMailer preMailer = new PreMailer.Net.PreMailer(mailInfo.BodyHtml);
            if (mailInfo.Utm.HasValidUtmCode)
            {
                preMailer.AddAnalyticsTags(mailInfo.Utm.Source, mailInfo.Utm.Medium, mailInfo.Utm.Campaign,
                    mailInfo.Utm.Content);
            }
            InlineResult cssInline = preMailer.MoveCssInline();
            mailInfo.BodyHtml = cssInline.Html;

            // Log any messages, debug is only detected
            // if we have an HttpContext.
            if (IsInDebugMode())
            {
                log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers.");
                log.WarningMessages.AddRange(cssInline.Warnings.ToArray());
            }

            // Loop through receivers collection, add to collection and send
            // one email per batch size.
            int batchRun = 0;
            int batchSize = GetBatchSize();

            do
            {
                IEnumerable<JobWorkItem> workItems = recepients.Skip(batchRun*batchSize).Take(batchSize);
                int numberofItemsToSend = workItems.Count();
                if (numberofItemsToSend == 0)
                    break;
                batchRun++;

                try
                {
                    if (SendMailBatch(mailInfo, workItems, testMode))
                    {
                        // Mark each item as sent
                        foreach (JobWorkItem workItem in workItems)
                        {
                            log.SuccessMessages.Add(workItem.EmailAddress);
                            // Update status and save it
                            workItem.Status = JobWorkStatus.Complete;
                            // Only save if real work item (could be a test item)
                            if (workItem.JobId > 0)
                                workItem.Save();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(string.Format("Error sending batch (to {0} recipients).", recepients.Count()), ex);
                    string exceptionMsg = ex.Message;
                    log.ErrorMessages.Add(exceptionMsg);

                    // Update work item
                    foreach (JobWorkItem workItem in workItems)
                    {
                        workItem.Status = JobWorkStatus.Failed;
                        if (exceptionMsg.Length >= 2000)
                            exceptionMsg = exceptionMsg.Substring(0, 1999);
                        workItem.Info = exceptionMsg;
                        if (workItem.JobId > 0)
                            workItem.Save();
                    }

                    // can't continue
                    break;
                }
            } while (true);

            // Finished
            log.SendStop = DateTime.Now;

            _log.Debug("Ending Send");
            // return report
            return log;
        }
        /// <summary>
        /// Creates the aspNET EmailMessage object based on mail information
        /// we've alread got. Construct the message from html, and then spesify
        /// that the images should be attached inline.
        /// </summary>
        /// <param name="mailInfo">Mail info.</param>
        /// <returns></returns>
        private EmailMessage CreateMessage(MailInformation mailInfo)
        {
            if (_log.IsDebugEnabled())
            {
                _log.Debug("Begin CreateMessage. Base Url: {0}", mailInfo.BaseUrl);
            }

            EmailMessage email   = new EmailMessage();
            HtmlUtility  utility = new HtmlUtility(email);

            // Swallow exceptions if configured
            if (Configuration.NewsLetterConfiguration.DisableExceptionsInMailRendering == true)
            {
                email.ThrowException = false;
            }

            // Troubleshooting needs logging
            if (Configuration.NewsLetterConfiguration.ExtendedLogFile != null)
            {
                // Be careful with logging, it will generate large amounts of log data
                email.LogInMemory        = false;
                email.LogPath            = EPiServer.Global.BaseDirectory + Configuration.NewsLetterConfiguration.ExtendedLogFile;
                email.LogDebugStatements = true;
                email.LogBody            = true;
                email.Logging            = true;
            }

            // set all relative links contained in the html to this url
            string baseUrl = SiteDefinition.Current.SiteUrl.ToString();

            if (string.IsNullOrEmpty(mailInfo.BaseUrl) == false)
            {
                baseUrl = mailInfo.BaseUrl;
            }

            // Resolves Hrefs to their absolute value, this means
            // no urls in the html will be relative (which can be a pain
            // depending on the markup
            utility.ResolveHrefs = true;

            // Clean html, remove tags and content we do not want or need
            utility.HtmlRemovalOptions = HtmlRemovalOptions.AppletTag |
                                         HtmlRemovalOptions.EmbedTag |
                                         HtmlRemovalOptions.NoScriptTag |
                                         HtmlRemovalOptions.ObjectTag |
                                         HtmlRemovalOptions.ParamTag |
                                         HtmlRemovalOptions.Scripts |
                                         HtmlRemovalOptions.ViewState |
                                         HtmlRemovalOptions.EventArgument |
                                         HtmlRemovalOptions.EventTarget;

            // Load the html mail
            utility.LoadString(mailInfo.BodyHtml, baseUrl);

            // Set the UrlContent base
            utility.SetUrlContentBase = false;

            // Set the basetag in the html
            utility.SetHtmlBaseTag = true;

            // Embed the images into the email message, using the
            // content id as a src reference. Change this if you do
            // not want images to be part of the message
            utility.EmbedImageOption = EmbedImageOption.ContentId;

            // If you have problems loading images, disable exceptions
            // if (utility.ParentMessage != null)
            //    utility.ParentMessage.ThrowException = false;

            //render the Html so it is properly formatted for email
            utility.Render();

            //render an EmailMessage with appropriate text and html parts
            email = utility.ToEmailMessage();

            //load remaining properties from web.config
            email.LoadFromConfig();

            // Try to get these encodings correct
            email.ContentTransferEncoding = MailEncoding.QuotedPrintable;

            // Using utf-8 would have been nice, but utf-8 is not widely
            // adopted by email clients it seems.
            // email.CharSet = "utf-8";

            // Using iso 8859-1 hotmail will show Norwegian characters
            // even if the user runs with english settings
            // Hotmail needs this
            email.CharSet = "iso-8859-1";

            // Override with our own values
            email.Subject      = mailInfo.Subject;
            email.From         = mailInfo.From;
            email.TextBodyPart = mailInfo.BodyText;

            if (_log.IsDebugEnabled())
            {
                _log.Debug("Rendered Mail Message: {0}", email.Subject);
            }

            return(email);
        }
Example #18
0
 /// <summary>
 /// Send mail to mailreceivers using System.Web.Mail 
 /// </summary>
 /// <param name="mailInfo">A MailInformation object with the content to send</param>
 /// <param name="recepients">receivers</param>
 /// <param name="testMode">No mails are sent, generating report for user</param>
 /// <returns>A report of the send process</returns>
 public abstract SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode);
 public abstract bool SendMailBatch(MailInformation mail, IEnumerable<JobWorkItem> recipients, bool onlyTestDontSendMail);
Example #20
0
        /// <summary>
        /// Send mail to mailreceivers using Mailgun REST API
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recepients">receivers</param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A html formatted report of the send process</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode)
        {
            _log.Debug("Starting Mailgun Send");

            // Inline all css
            InlineResult cssInline = PreMailer.Net.PreMailer.MoveCssInline(mailInfo.BodyHtml);
            mailInfo.BodyHtml = cssInline.Html;

            // Base will send
            SendMailLog log = base.SendEmail(mailInfo, recepients, testMode);

            // Log any messages, debug is only detected
            // if we have an HttpContext.
            if (IsInDebugMode())
            {
                log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers.");
                log.WarningMessages.AddRange(cssInline.Warnings.ToArray());
            }

            _log.Debug("Ending Mailgun Send");
            // return report
            return log;
        }
Example #21
0
        public MailInformation GetHtmlReport(string from, string subject, bool ShowSuccessAddresses)
        {
            if (from == null)
                throw new ArgumentNullException("from", "From email address cannot be null");

            MailInformation mailInfo = new MailInformation();
            mailInfo.Subject = subject;
            mailInfo.From = from;

            System.Text.StringBuilder reportMailBody = new System.Text.StringBuilder();
            reportMailBody.AppendLine("<div id=\"MailReport\">");

            // Start send
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Started send:</span> <span class=\"onelinesectionvalue\">{0}</span></span></div>", this.SendStart.ToString());

            // Start send
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">End send:</span> <span class=\"onelinesectionvalue\">{0}</span></div>", this.SendStop.ToString());

            // Duration
            TimeSpan duration = TimeSpan.FromMilliseconds((double)this.TotalDuration);
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Duration:</span> <span class=\"onelinesectionvalue\">{0}hr {1}min {2}sec</span></div>", duration.Hours.ToString(), duration.Minutes.ToString(), duration.Seconds.ToString());

            // Number of emails sent
            reportMailBody.AppendFormat("<div class=\"onelinesection\"><span class=\"onelinesectionlabel\">Number of emails sent:</span> <span class=\"onelinesectionvalue\">{0}</span></div>", this.NumberOfEmailsSent.ToString());

            // Exceptions first
            if (ErrorMessages.Count > 0)
                AppendMultiLineSectionAsHtml("Exceptions", ErrorMessages, reportMailBody);

            // Warnings next
            if (WarningMessages.Count > 0)
                AppendMultiLineSectionAsHtml("Warnings", WarningMessages, reportMailBody);

            // Successfull HTML Text Recipients
            if (ShowSuccessAddresses == true)
                AppendMultiLineSectionAsHtml("Successfull HTML Format Recipients", SuccessMessages, reportMailBody);

            reportMailBody.AppendLine("</div>");
            mailInfo.BodyHtml = reportMailBody.ToString();

            return mailInfo;
        }
Example #22
0
        public override bool SendMailBatch(MailInformation mail, IEnumerable <JobWorkItem> recipients, bool onlyTestDontSendMail)
        {
            MailgunSettings settings = GetSettings();

            // ReSharper disable PossibleMultipleEnumeration
            if (recipients == null || recipients.Count() == 0)
            {
                throw new ArgumentException("No workitems", "recipients");
            }

            if (recipients.Count() > 1000)
            {
                throw new ArgumentOutOfRangeException("recipients", "Mailgun supports maximum 1000 recipients per batch send.");
            }

            RestClient client = new RestClient();

            client.BaseUrl       = new Uri("https://api.mailgun.net/v2");
            client.Authenticator = new HttpBasicAuthenticator("api", settings.ApiKey);

            if (string.IsNullOrEmpty(settings.ProxyAddress) == false)
            {
                client.Proxy = new WebProxy(settings.ProxyAddress, settings.ProxyPort); // Makes it easy to debug as Fiddler will show us the requests
            }

            RestRequest request = new RestRequest();

            request.AlwaysMultipartFormData = true;
            request.AddParameter("domain", settings.Domain, ParameterType.UrlSegment);
            request.Resource = "{domain}/messages";
            request.AddParameter("from", mail.From);
            request.AddParameter("subject", mail.Subject);
            request.AddParameter("text", mail.BodyText);
            request.AddParameter("html", mail.BodyHtml);

            if (mail.EnableTracking)
            {
                request.AddParameter("o:tracking", mail.EnableTracking);
                request.AddParameter("o:tracking-clicks", mail.EnableTracking);
                request.AddParameter("o:tracking-opens", mail.EnableTracking);
            }

            foreach (KeyValuePair <string, object> customProperty in mail.CustomProperties)
            {
                request.AddParameter(customProperty.Key, customProperty.Value.ToString());
            }

            // Add custom data about job
            if (mail.CustomProperties.ContainsKey("v:newsletter-data") == false)
            {
                request.AddParameter("v:newsletter-data",
                                     string.Format("{{\"id\": \"{0}\", \"page\": \"{1}\" }}",
                                                   recipients.First().JobId, mail.PageLink.ID));
            }

            // Add all recipients
            StringBuilder recipVariables = new StringBuilder();
            bool          first          = true;

            foreach (JobWorkItem recipient in recipients)
            {
                request.AddParameter("to", recipient.EmailAddress);

                if (first == false)
                {
                    recipVariables.Append(",");
                }
                first = false;
                recipVariables.AppendFormat("\"{0}\" : {{\"id\": \"{1}\" }}", recipient.EmailAddress, recipient.GetHashCode());
            }
            request.AddParameter("recipient-variables", "{" + recipVariables.ToString() + "}");

            //if(onlyTestDontSendMail)
            //{
            //    request.AddParameter("o:testmode", true);
            //}

            request.Method = Method.POST;
            var response = client.Execute(request);

            Dictionary <string, string> resultParams = null;

            try
            {
                resultParams = new JsonDeserializer().Deserialize <Dictionary <string, string> >(response);
            }
            catch (Exception e)
            {
                _log.Warning("Unable to parse Mailgun response.", e);
            }

            if (response.StatusCode == HttpStatusCode.OK)
            {
                _log.Debug("Mailgun responded with: {0} - {1}", response.StatusCode, response.StatusDescription);
                if (string.IsNullOrEmpty(response.ErrorMessage) == false)
                {
                    _log.Error("Response Error: {0}", response.ErrorMessage);
                }
                _log.Debug(response.Content);

                // json looks like:
                //{
                //  "message": "Queued. Thank you.",
                //  "id": "<*****@*****.**>"
                //}

                // Update all recipients with information
                if (resultParams != null)
                {
                    string info = resultParams["id"];
                    foreach (JobWorkItem recipient in recipients)
                    {
                        recipient.Info = info;
                    }
                }
            }
            else
            {
                _log.Debug("Mailgun responded with: {0} - {1}", response.StatusCode, response.StatusDescription);
                string errorMessage = response.StatusDescription;
                if (resultParams != null)
                {
                    errorMessage = resultParams["message"];
                }

                if (string.IsNullOrEmpty(response.ErrorMessage) == false)
                {
                    _log.Error("Response Error: {0}", response.ErrorMessage);
                }
                _log.Debug(response.Content);

                throw new HttpException((int)response.StatusCode, errorMessage);
            }

            return(true);
            // ReSharper restore PossibleMultipleEnumeration
        }
        /// <summary>
        /// Send mail to mailreceivers using System.Web.Mail 
        /// </summary>
        /// <param name="mailInfo"></param>
        /// <param name="recipients"></param>
        /// <param name="testMode">No mails are sent, generating report for user</param>
        /// <returns>A SendMailLog object with information about the status of the job.</returns>
        public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recipients, bool testMode)
        {
            _log.Debug("900.10.11.1 Starting Send");
            // for logging
            SendMailLog log = new SendMailLog();
            log.StartJob();
            // Recipients util
            RecipientsUtility recipUtil = new RecipientsUtility();

            // We try to verify as many settings, variables etc. before
            // starting the sending loop, as we don't want to generate
            // lots of exceptions in a loop.

            // Need someone to send to
            if (recipients.Items.Count == 0)
            {
                _log.Error("900.10.11.2 Trying to send mail with an empty JobWorkItems collection. Please check the collection before attemting to send mail.");
                throw new ArgumentNullException("Recipient collection is empty, there is no recipients to send to.", "recepients");
            }

            // And, we need a sender address
            if (mailInfo.From == null || mailInfo.From == string.Empty)
            {
                _log.Error("900.10.11.3 Missing from address. SMTP servers do not allow sending without a sender.");
                throw new ArgumentNullException("Missing from address. SMTP servers do not allow sending without a sender.", "mailInfo.From");
            }

            // Load the license. This needs to be in the
            EmailMessage.LoadLicenseString(GetLicenseFileContents());

            // We'll reuse the mail object, so we create it outside of the loop
            EmailMessage mail = CreateMessage(mailInfo);

            // Set port and authentication details if found
            InitializeMailSettings(ref mail);

            // Send a warm-up message outside the loop. This
            // will help us catch any misconfigurations and other
            // things that prevents us from sending emails. By
            // doing this outside the loop, we won't kill the
            // application or log with uneccesary error messages.
            // TODO: Implement this

            // Loop through receivers collection, send email for each
            foreach (JobWorkItem workItem in recipients)
            {
                _log.Debug(string.Format("900.10.11.5 Job {0}, Email: {1}, Status: {2}",
                           workItem.JobId.ToString(), workItem.EmailAddress, workItem.Status.ToString()));

                // Only attempt sending those that have been stamped as ready for sending
                // unless we're in a test case.
                if (workItem.Status == JobWorkStatus.Sending || testMode == true)
                {

                    try
                    {
                        // At this point we assume the address is formatted correctly
                        // and checked, but aspNetEmail checks the to address on set, may fail
                        mail.To = workItem.EmailAddress;

                        // Perform actual send, if testmail, then this will
                        // return false. We should not update the status on
                        // test sends
                        bool result = SendMail(mail, testMode);
                        if (result == true)
                        {
                            log.SuccessMessages.Add(workItem.EmailAddress);

                            // Update status and save it
                            // TODO: Improve performance by doing this in batch
                            workItem.Status = JobWorkStatus.Complete;
                            // Only save if real work item (could be a test item)
                            if (workItem.JobId > 0)
                                workItem.Save();

                        }
                        // else
                        // Could not send, it has been disabled by
                        // settings or parameters

                    }
                    catch (Exception ex)
                    {
                        _log.Error(string.Format("900.10.11.6 Error sending to email: {0}", workItem.EmailAddress), ex);
                        string exceptionMsg = string.Format("Email: {0}\r\nException: {1}\r\n\r\n", workItem.EmailAddress, ex.Message);
                        log.ErrorMessages.Add(exceptionMsg);

                        // Update work item
                        workItem.Status = JobWorkStatus.Failed;
                        if (exceptionMsg.Length >= 2000)
                            exceptionMsg = exceptionMsg.Substring(0, 1999);
                        workItem.Info = exceptionMsg;
                        if (workItem.JobId > 0)
                            workItem.Save();
                    }
                }
                else
                {
                    _log.Debug(string.Format("900.10.11.7 Skipping Recipient, wrong status. Job {0}, Email: {1}, Status: {2}",
                              workItem.JobId.ToString(), workItem.EmailAddress, workItem.Status.ToString()));
                }
            }

            // Finished
            log.StopJob();

            // Warn user if logging is enabled
            if (Configuration.NewsLetterConfiguration.ExtendedLogFile != null)
                log.WarningMessages.Add("Logging has been enabled. Only use during troubleshooting.");

            _log.Debug("900.10.11.8 Ending Send");
            // return report
            return log;
        }
        /// <summary>
        /// Creates the aspNET EmailMessage object based on mail information
        /// we've alread got. Construct the message from html, and then spesify
        /// that the images should be attached inline.
        /// </summary>
        /// <param name="mailInfo">Mail info.</param>
        /// <returns></returns>
        private EmailMessage CreateMessage(MailInformation mailInfo)
        {
            if (_log.IsDebugEnabled())
                _log.Debug("Begin CreateMessage. Base Url: {0}", mailInfo.BaseUrl);

            EmailMessage email = new EmailMessage();
            HtmlUtility utility = new HtmlUtility(email);

            // Swallow exceptions if configured
            if (Configuration.NewsLetterConfiguration.DisableExceptionsInMailRendering == true)
                email.ThrowException = false;

            // Troubleshooting needs logging
            if (Configuration.NewsLetterConfiguration.ExtendedLogFile != null)
            {
                // Be careful with logging, it will generate large amounts of log data
                email.LogInMemory = false;
                email.LogPath = EPiServer.Global.BaseDirectory + Configuration.NewsLetterConfiguration.ExtendedLogFile;
                email.LogDebugStatements = true;
                email.LogBody = true;
                email.Logging = true;
            }

            // set all relative links contained in the html to this url
            string baseUrl = SiteDefinition.Current.SiteUrl.ToString();

            if (string.IsNullOrEmpty(mailInfo.BaseUrl) == false)
                baseUrl = mailInfo.BaseUrl;

            // Resolves Hrefs to their absolute value, this means
            // no urls in the html will be relative (which can be a pain
            // depending on the markup
            utility.ResolveHrefs = true;

            // Clean html, remove tags and content we do not want or need
            utility.HtmlRemovalOptions = HtmlRemovalOptions.AppletTag |
                                        HtmlRemovalOptions.EmbedTag |
                                        HtmlRemovalOptions.NoScriptTag |
                                        HtmlRemovalOptions.ObjectTag |
                                        HtmlRemovalOptions.ParamTag |
                                        HtmlRemovalOptions.Scripts |
                                        HtmlRemovalOptions.ViewState |
                                        HtmlRemovalOptions.EventArgument |
                                        HtmlRemovalOptions.EventTarget;

            // Load the html mail
            utility.LoadString(mailInfo.BodyHtml, baseUrl);

            // Set the UrlContent base
            utility.SetUrlContentBase = false;

            // Set the basetag in the html
            utility.SetHtmlBaseTag = true;

            // Embed the images into the email message, using the
            // content id as a src reference. Change this if you do
            // not want images to be part of the message
            utility.EmbedImageOption = EmbedImageOption.ContentId;

            // If you have problems loading images, disable exceptions
            // if (utility.ParentMessage != null)
            //    utility.ParentMessage.ThrowException = false;

            //render the Html so it is properly formatted for email
            utility.Render();

            //render an EmailMessage with appropriate text and html parts
            email = utility.ToEmailMessage();

            //load remaining properties from web.config
            email.LoadFromConfig();

            // Try to get these encodings correct
            email.ContentTransferEncoding = MailEncoding.QuotedPrintable;

            // Using utf-8 would have been nice, but utf-8 is not widely
            // adopted by email clients it seems.
            // email.CharSet = "utf-8";

            // Using iso 8859-1 hotmail will show Norwegian characters
            // even if the user runs with english settings
            // Hotmail needs this
            email.CharSet = "iso-8859-1";

            // Override with our own values
            email.Subject = mailInfo.Subject;
            email.From = mailInfo.From;
            email.TextBodyPart = mailInfo.BodyText;

            if (_log.IsDebugEnabled())
                _log.Debug("Rendered Mail Message: {0}", email.Subject);

            return email;
        }