0

I have method that execute Email sender like this:

public void SendIt() 
{
    if (_Error && !_Override) return;

    var html = new StringBuilder();
    html.Append(HTMLHeader());
    html.Append(Body);
    html.Append(HTMLClose());

    IsHTML = true;
    SendAsync = true;
    Body = html.ToString();
    Send();
}

I want to change this method to asynchronous method so I do:

public async void SendIt() 
{
    await Send();
}

But I get

'bool' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'bool' could be found (are you missing a using directive or an assembly reference?)

Send method:

public bool Send() 
{
    var MailFrom = new MailAddress(_From, _From);
    _Email.From = MailFrom;

    if (_To.IndexOf(';') > -1) 
    {
        string[] tolist = _To.Split(';');
        foreach (string toAddress in tolist) 
            _Email.To.Add(new MailAddress(toAddress.Trim()));
    }
    else _Email.To.Add(new MailAddress(_To.Trim()));        

    if (_CC != null && _CC.Length > 5) 
    {
        if (_CC.IndexOf(';') > -1) 
        {
            string[] Cclist = _CC.Split(';');
            foreach (string ccAddress in Cclist) 
                _Email.CC.Add(new MailAddress(ccAddress.Trim()));
        }
        else _Email.CC.Add(new MailAddress(_CC.Trim()));
    }

    if (_BCC != null && _BCC.Length > 5) 
    {
        if (_BCC.IndexOf(';') > -1) 
        {
            string[] Bcclist = _BCC.Split(';');
            foreach (string bccAddress in Bcclist) 
               _Email.Bcc.Add(new MailAddress(bccAddress.Trim()));
        }
        else _Email.Bcc.Add(new MailAddress(_BCC.Trim()));
    }

    _Email.Subject      = _Subject;
    _Email.IsBodyHtml   = _isHTML;
    _Email.Body         = _Body;
    _Email.BodyEncoding = Encoding.UTF8;

    // Smtp Client
    var Connection = new SmtpClient(_Server, _Port) 
    {
        DeliveryMethod = SmtpDeliveryMethod.Network,
        Timeout = 60000
    };

    if (_UserName.Length > 1 && _Password.Length > 1 && _Domain.Length > 1) 
        Connection.Credentials = new NetworkCredential(_UserName, _Password, _Domain);
    else if (_UserName.Length > 1 && _Password.Length > 1) 
        Connection.Credentials = new NetworkCredential(_UserName, _Password);

    bool bFlag = true;

    Connection.EnableSsl = _SSL;

    try 
    {
        Connection.Send(_Email);
    } 
    catch (SmtpFailedRecipientsException ex) 
    {
        var msg = new StringBuilder();

        for (int k = 0; k < ex.InnerExceptions.Length; k++) 
        {
            var StatusCode = ex.InnerExceptions[k].StatusCode;

            if (StatusCode == SmtpStatusCode.MailboxUnavailable || StatusCode == SmtpStatusCode.MailboxBusy) 
            {
                ErrMsg = "Failed to deliver message to " + ex.FailedRecipient[k].ToString();

                try 
                {
                    if (_TryAgainOnFailure) 
                    {
                        System.Threading.Thread.Sleep(_TryAgainDelayTime);

                        // Send the message
                        string sTemp = "";
                        if (_SendAsync) 
                            Connection.SendAsync(_Email, sTemp);
                        else Connection.Send(_Email);
                    }
                    _ErrMsg = string.Empty;
                } 
                catch (SmtpException sex) 
                {
                    _ErrMsg = sex.Message;
                    _Error = true;
                }
            }
        }
    } 
    catch (SmtpException sex) 
    {
        string dat = sex.Data.ToString();
        _ErrMsg = sex.Message;
        _Error = true;
    }
    return bFlag;
}

How can I convert this boolean method to async method?

I try something like:

public async bool Send() {

But I get:

The return type of an async method must be void, Task or Task

What should I do to solve this? Regards

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Pepe
  • 57
  • 4
  • It's possible answers to [this existing question](https://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await) may address your issue. The [Microsoft documentation on asynchronous programming](https://learn.microsoft.com/en-us/dotnet/csharp/async) may also help. – Frank Boyne Sep 05 '18 at 20:14
  • Your `Send` method is very long and needs to be refactored into smaller methods. By looking at it, it seems you repeat the same code a few times. The repeated parts needs to be their own methods, and you can use parameters to control the differences for the tiny differences between each time you rewrote it. – AustinWBryan Sep 05 '18 at 21:11

2 Answers2

2

The return type of an async method must be void, Task or Task<T>

Like the error states you have to change the return type to Task<bool>. You will then have to change the method itself so it awaits a Task or returns a Task.

public async Task<Boolean> SendAsync() { // renamed your method with suffix Async

    // ... code unchanged
    try {
        await Connection.SendMailAsync(this._Email);
    } 
    // ... code unchanged
}

As for your other methods that call this they should also return type Task unless they are event driven like a windows form or wpf click event.

See also SendMailAsync

Igor
  • 60,821
  • 10
  • 100
  • 175
1

You must return Task<T> if you use async method.

Correct definition for your method is:

public async Task<Boolean> Send()

Also you need to use await keyword inside your method.

You can write Send method using SendMailAsync.

Example is here:

public async Task Send(string to, string subject, string body)
{
    var message = new MailMessage
    {
        Subject = subject,
        Body = body
    };
    message.To.Add(to);

    using (var smtpClient = new SmtpClient())
    {
        await smtpClient.SendMailAsync(message);
    }
} 

More details you can review here.

Also please review details about async/await programming here.

Alexander I.
  • 2,380
  • 3
  • 17
  • 42