Электронная почта Gmail не отправляется при вызове из пула потоков - PullRequest
0 голосов
/ 09 февраля 2012

Я пытаюсь отправлять сообщения электронной почты асинхронно, однако, когда я вызываю свой метод SendMailMesage () из Threadpool или простого потока, электронные письма просто не отправляются.

В любом случае какдля достижения этой цели?Регулярная отправка электронной почты sendind значительно замедляет мое приложение.

PS: если это имеет значение, SendMailMesage () отправляется из ссылочного проекта, а не самого проекта MVC.

Спасибо.

Редактировать: Мой код.

namespace App.Core.Utils.Mailer
{
    public static class Sender
    {
        /// <summary>
        /// Sends a MailMessage object using the SMTP settings.
        /// </summary>
        public static void SendMailMessage(MailMessage message)
        {
            if (!Settings.Instance.SendEmails)
            {
                return;
            }

            if (message == null)
                throw new ArgumentNullException("message");

            try
            {
                message.IsBodyHtml = true;
                message.BodyEncoding = Encoding.UTF8;
                var smtp = new SmtpClient(Settings.Instance.SmtpServer);

                // don't send credentials if a server doesn't require it,
                // linux smtp servers don't like that 
                if (!string.IsNullOrEmpty(Settings.Instance.SmtpUserName))
                {
                    smtp.Credentials = new System.Net.NetworkCredential(Settings.Instance.SmtpUserName, Settings.Instance.SmtpPassword);
                }
                smtp.Port = Settings.Instance.SmtpServerPort;
                smtp.EnableSsl = Settings.Instance.EnableSsl;
                smtp.Send(message);
            }
            catch (SmtpException)
            {
                //OnEmailFailed(message);
            }
            finally
            {
                // Remove the pointer to the message object so the GC can close the thread.
                message.Dispose();
            }
        }

        public static void SendMailMessageAsync(MailMessage message)
        {
            ThreadPool.QueueUserWorkItem(state => SendMailMessage(message));
        } 
    }
}

Примечание: это работает в WebForms.Я скопировал код в проект MVC, и теперь ничего не отправляется, если я вызываю метод SendMailMessageAsync.Ошибок тоже нет.

1 Ответ

1 голос
/ 09 февраля 2012

Мы используем это в MVC, и это прекрасно работает. Поскольку он реализует интерфейс, вы можете внедрить экземпляр в конструктор контроллера вместо использования статического метода:

public class MvcEmailSender : ISendEmails
{
    public MvcEmailSender(ILogExceptions logger, 
        IQueryEntities queryables, IUnitOfWork unitOfWork)
    {
        // save args to readonly fields on the instance
    }

    public void Send(EmailMessage message)
    {
        // constructor really passes more args here
        var sender = new SmtpEmailSender(message, arg2, arg3, arg4);
        var thread = new Thread(sender.Send);
        thread.Start();
    }
}

public class SmtpEmailSender
{
    private readonly EmailMessage _emailMessage;
    private int _retryCount;

    public SmtpEmailSender(EmailMessage emailMessage, ILogExceptions logger,
        IQueryEntities queryables, IUnitOfWork unitOfWork)
    {
        if (emailMessage == null)
            throw new ArgumentNullException("emailMessage");

        _emailMessage = emailMessage;
        // save other constructor args to readonly fields
    }

    public void Send()
    {
        try
        {
            // assemble message, send, & update database
        }
        catch (Exception ex)
        {
            // log exception, then retry like so:
            if (_retryCount++ <= 3)
            {
                Thread.Sleep(10000);
                Send();
            }
        }
    }
}

У нас также есть некоторые настройки в файле web.config, а вы? Если это так, обновите ваш вопрос с помощью раздела system.net в вашем web.config.

Чтобы использовать это, мы просто вызываем ISendEmails.Send (EmailMessage) из контроллера. Реализация заботится о потоке, без ведома MVC.

Оба эти класса и интерфейс ISendEmails объявлены в ссылочных проектах, а не в проекте MVC (интерфейс находится в сборке API, а 2 вышеупомянутых класса в сборке IMPL).

Обновление

Я обновил код в ответ на комментарий. Обратите внимание, что конструкторы этих классов действительно имеют больше зависимостей, чем было изначально изображено. Мы также (конструктор) внедряем зависимости ILogExceptions, IQueryEntities и IUnitOfWork. Внутри блока try, помимо преобразования EmailMessage в MailMessage и отправки, объект домена EmailMessage обновляется в базе данных, а его значение SentOnUtc обновляется после успешного выполнения SmtpClient.Send (MailMessage). Вот как мы доказываем, что электронные письма были действительно отправлены. При обнаружении исключения оно регистрируется перед повторной попыткой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...