Асинхронно посылающие электронные письма в C#?

Я разрабатываю приложение, где пользователь, щелчки/нажатия вводят в определенную кнопку в окне, приложение, делает некоторые проверки и определяет, послать ли несколько электронных писем или нет, затем покажите другое окно с сообщением.

Моя проблема, посылание этих 2 электронных писем замедляет процесс заметно, и приблизительно для (~8) секунды первое окно выглядит замороженным, в то время как это делает отправку.

Есть ли какой-либо способ, которым мне можно было отправить эти электронные письма на фоне и отобразить следующее окно сразу же?

Не ограничивайте свой ответ с "использованием, X классов" или "просто используют X методов", поскольку я еще слишком не ознакомлен с языком, и еще некоторая информация высоко ценилась бы.

Спасибо.

35
задан Eton B. 4 August 2010 в 18:05
поделиться

8 ответов

Поскольку это небольшая единица работы, вы должны использовать ThreadPool.QueueUserWorkItem для его многопоточности. Если вы используете класс SmtpClient для отправки вашей почты, вы можете обработать событие SendCompleted , чтобы оставить отзыв для пользователя.

ThreadPool.QueueUserWorkItem(t =>
{
    SmtpClient client = new SmtpClient("MyMailServer");
    MailAddress from = new MailAddress("me@mydomain.com", "My Name", System.Text.Encoding.UTF8);
    MailAddress to = new MailAddress("someone@theirdomain.com");
    MailMessage message = new MailMessage(from, to);
    message.Body = "The message I want to send.";
    message.BodyEncoding =  System.Text.Encoding.UTF8;
    message.Subject = "The subject of the email";
    message.SubjectEncoding = System.Text.Encoding.UTF8;
    // Set the method that is called back when the send operation ends.
    client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
    // The userState can be any object that allows your callback 
    // method to identify this send operation.
    // For this example, I am passing the message itself
    client.SendAsync(message, message);
});

private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
        // Get the message we sent
        MailMessage msg = (MailMessage)e.UserState;

        if (e.Cancelled)
        {
            // prompt user with "send cancelled" message 
        }
        if (e.Error != null)
        {
            // prompt user with error message 
        }
        else
        {
            // prompt user with message sent!
            // as we have the message object we can also display who the message
            // was sent to etc 
        }

        // finally dispose of the message
        if (msg != null)
            msg.Dispose();
}

Создавая новый SMTP-клиент каждый раз, вы сможете одновременно отправлять электронные письма.

24
ответ дан 27 November 2019 в 06:25
поделиться

Нет ничего сложного в том, чтобы просто отправить сообщение в отдельном потоке:

using System.Net.Mail;

Smtp.SendAsync(message);

Или, если вы хотите создать все сообщение в отдельном потоке, а не просто отправлять его в асинхронном режиме:

using System.Threading;
using System.Net.Mail;

var sendMailThread = new Thread(() => {
    var message=new MailMessage();
    message.From="from e-mail";
    message.To="to e-mail";
    message.Subject="Message Subject";
    message.Body="Message Body";

    SmtpMail.SmtpServer="SMTP Server Address";
    SmtpMail.Send(message);
});

sendMailThread.Start();
12
ответ дан 27 November 2019 в 06:25
поделиться

Метод SmtpClient.SendAsync

Пример

using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.ComponentModel;
namespace Examples.SmptExamples.Async
{
    public class SimpleAsynchronousExample
    {
        static bool mailSent = false;
        private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
        {
            // Get the unique identifier for this asynchronous operation.
             String token = (string) e.UserState;

            if (e.Cancelled)
            {
                 Console.WriteLine("[{0}] Send canceled.", token);
            }
            if (e.Error != null)
            {
                 Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
            } else
            {
                Console.WriteLine("Message sent.");
            }
            mailSent = true;
        }
        public static void Main(string[] args)
        {
            // Command line argument must the the SMTP host.
            SmtpClient client = new SmtpClient(args[0]);
            // Specify the e-mail sender. 
            // Create a mailing address that includes a UTF8 character 
            // in the display name.
            MailAddress from = new MailAddress("jane@contoso.com", 
               "Jane " + (char)0xD8+ " Clayton", 
            System.Text.Encoding.UTF8);
            // Set destinations for the e-mail message.
            MailAddress to = new MailAddress("ben@contoso.com");
            // Specify the message content.
            MailMessage message = new MailMessage(from, to);
            message.Body = "This is a test e-mail message sent by an application. ";
            // Include some non-ASCII characters in body and subject. 
            string someArrows = new string(new char[] {'\u2190', '\u2191', '\u2192', '\u2193'});
            message.Body += Environment.NewLine + someArrows;
            message.BodyEncoding =  System.Text.Encoding.UTF8;
            message.Subject = "test message 1" + someArrows;
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            // Set the method that is called back when the send operation ends.
            client.SendCompleted += new 
            SendCompletedEventHandler(SendCompletedCallback);
            // The userState can be any object that allows your callback  
            // method to identify this send operation. 
            // For this example, the userToken is a string constant. 
            string userState = "test message1";
            client.SendAsync(message, userState);
            Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.");
            string answer = Console.ReadLine();
            // If the user canceled the send, and mail hasn't been sent yet, 
            // then cancel the pending operation. 
            if (answer.StartsWith("c") && mailSent == false)
            {
                client.SendAsyncCancel();
            }
            // Clean up.
            message.Dispose();
            Console.WriteLine("Goodbye.");
        }
    }
}
8
ответ дан 27 November 2019 в 06:25
поделиться

Попробуйте следующее:

var client = new System.Net.Mail.SmtpClient("smtp.server");
var message = new System.Net.Mail.MailMessage() { /* provide its properties */ };
client.SendAsync(message, null);
4
ответ дан 27 November 2019 в 06:25
поделиться

Что вы хотите сделать, так это запустить задачу электронной почты в отдельном потоке, чтобы основной код мог продолжить обработку, в то время как другой поток выполняет работу с электронной почтой.

Вот инструкция, как это сделать: Учебник по многопоточности C #

1
ответ дан 27 November 2019 в 06:25
поделиться

Используя Task Parallel Library в .NET 4.0, вы можете:

Parllel.Invoke(() => { YourSendMailMethod(); });

Также см. cristina manu's Сообщение в блоге о Parallel.Invoke () и явном управлении задачами.

1
ответ дан 27 November 2019 в 06:25
поделиться

Просто потому что это немного туманно... я буду краток...

Есть много способов сделать асинхронную или параллельную работу в c#/.net и т.д.

Самый быстрый способ сделать то, что вы хотите - использовать фоновый рабочий поток, который позволит избежать блокировки вашего пользовательского интерфейса.

Совет по поводу фоновых рабочих потоков: вы не можете напрямую обновлять пользовательский интерфейс из них (сродство потоков и Marshalling - это то, с чем вы научитесь справляться...)

Еще одна вещь, которую нужно учесть... если вы используете стандартный System.Net.Mail для отправки писем... будьте осторожны с логикой. Если вы изолируете все это в каком-то методе и будете вызывать его снова и снова, ему, скорее всего, придется каждый раз разрывать и восстанавливать соединение с почтовым сервером, а задержки, связанные с аутентификацией и т.д., будут излишне замедлять работу. По возможности отправляйте несколько электронных писем через одно открытое соединение с почтовым сервером.

5
ответ дан 27 November 2019 в 06:25
поделиться

Используйте класс SmtpClient и используйте метод SendAsync в пространстве имен System.Net.Mail.

2
ответ дан 27 November 2019 в 06:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: