amazon-web-servicesasynchronous.net-coreaws-lambdamailjet

AWS lambda, C# async mail sending issue - MailJet API


I was originally using AWS SES for mail sending from my Lambda, but it has very slow delivery.

I then decided to switch to MailJet and use their API for sending mails. I am using the NuGet package, V3.1 of the API, and pretty much the sample code from MailJet to send the mails async.

    public async Task<bool> SendEmailAsync(EmailModel model)
    {            
        Boolean sent = false;

        MailjetClient client = new MailjetClient(Environment.GetEnvironmentVariable("EmailAPIKey"), Environment.GetEnvironmentVariable("EmailAPISecret"))
        {
            Version = ApiVersion.V3_1,
        };

        MailjetRequest request = new MailjetRequest
        {
            Resource = Send.Resource,
        }.Property(Send.Messages, new JArray {
             new JObject {
                 {"From", new JObject {
                         {"Email", Environment.GetEnvironmentVariable("SenderEmail")},
                         {"Name", Environment.GetEnvironmentVariable("SenderEmailName")}
                     }
                 },
                 {"HTMLPart", model.EmailHtmlBody},
                 {"Subject", model.EmailSubject},
                 {"TextPart", model.EmailTextBody},
                 {"To", new JArray {
                     new JObject {
                         {"Email", model.EmailTo},
                         {"Name", model.EmailTo}
                     }
                 }}
             }
            });

        try
        {
            MailjetResponse response = await client.PostAsync(request);

            if (response.IsSuccessStatusCode)
            {
                sent = true;
                LambdaLogger.Log(string.Format("Total: {0}, Count: {1}\n", response.GetTotal(), response.GetCount()));
                LambdaLogger.Log(response.GetData().ToString());
            }
            else
            {
                sent = false;
                LambdaLogger.Log(string.Format("StatusCode: {0}\n", response.StatusCode));
                LambdaLogger.Log(string.Format("ErrorInfo: {0}\n", response.GetErrorInfo()));
                LambdaLogger.Log(response.GetData().ToString());
                LambdaLogger.Log(string.Format("ErrorMessage: {0}\n", response.GetErrorMessage()));
            }
        }
        catch (Exception mailFail)
        {
            sent = false;
            LambdaLogger.Log(string.Format("Failed: {0}\n", mailFail.Message.ToString() + " : " + mailFail.InnerException.Message.ToString()));
        }
   
        return sent;
    }

When I test the code locally everything works just fine.

When I deploy the lambda to AWS and call the method for sending mails, it is completely random if the mail is send. I am guessing it is the async part which fails for some reason, I am hoping someone can help me to figure this out, because for now I am stuck on this issue.

Or if someone can tell me how to get Amazon SES to send without delay.


Solution

  • From the question:

    it is completely random

    And from a comment:

    it seems like the lambda just keeps running and does not wait for the reply from MailJet

    It is sounding like an async/await issue, but probably not where you think. Note that you are correctly awaiting the result of the MailJet operation:

    MailjetResponse response = await client.PostAsync(request);
    

    But that's only in this method. This method is of course async:

    public async Task<bool> SendEmailAsync(EmailModel model)
    

    When you call this method, do you await it? The method where you call it, that should also be async. Do you await that? Basically, are you "async all the way down"?

    It sounds like somewhere in the codebase there's an async operation that's being invoked and then forgotten.