This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed last year.
Note: To the moderator that closed this, it's completely different from the generic nullref question. If you read my post, it's obviously specific to SendGrid.
I believe I'm following pretty close to documented SendGrid usage:
public async Task<string> SendEmailSendGrid(string emailTo, string subject, string body) {
var apiKey = SafeTrim(ConfigurationManager.AppSettings["SendGridAPIKey"]);
var client = new SendGridClient(apiKey);
var from = new EmailAddress(SafeTrim(ConfigurationManager.AppSettings["SendGridEmail"]));
var to = new EmailAddress(emailTo);
var msg = MailHelper.CreateSingleEmail(from, to, subject, string.Empty, body);
try {
var response = await client.SendEmailAsync(msg);
//return response;
return "SUCCESS";
} catch (Exception ex) {
return "ERROR in SendEmailSendGrid(): " + ex.Message;
}
}
And the caller:
var result = utils.SendEmailSendGrid(decodedEmail, "email test", "This is a test email using SendGrid.");
And the error I get every time EVEN THOUGH IT WORKS and the email actually sends and arrives in my inbox:
Object reference not set to an instance of an object.
I verified that all my variables are populated as expected - none are null or empty. I am passing an empty string to the plain text param (because I always want HTML contents), but I also tried passing that some content and it made no difference; same error.
A strange thing: this blows up so hard that my catch block is never entered. Instead, as soon as the exception is thrown, this full-screen window comes up in my VS2022:
So it is working and sending the email, but why the heavy crash? What am I doing wrong?
Can you try this my approach.
I am using a single instance approach, try it and lets see.
public async Task SendAsync(IdentityMessage message)
{
var apiKey = new MvcApplication().SENDGRID_APIKEY;
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("noreply#questersworld.net", "Questersworld Team"),
Subject = message.Subject,
HtmlContent = "<table width=\"80%\"><tr><td><img src=\"http://www.questersworld.net/Images/quester.png\" width=\"50\" height=\"50\"> Questers World <p><strong>Welcome, Questersworld Participant!</strong></p><br> We value your connection.<br><p>" + message.Body + "</p><p>visit www.questersworld.net </p><br><strong>© Questersworld.net</strong></td></tr></table>"
};
msg.AddTo(new EmailAddress(message.Destination, "Questersworld Participant"));
var response = await client.SendEmailAsync(msg);
}
Don't mind my info. Just try this and see
Related
Note: To the moderator that incorrectly closed this question, it's completely different from the generic nullref question. This is specific to SendGrid.
I believe I'm following pretty close to documented SendGrid usage:
public async Task<string> SendEmailSendGrid(string emailTo, string subject, string body) {
var apiKey = SafeTrim(ConfigurationManager.AppSettings["SendGridAPIKey"]);
var client = new SendGridClient(apiKey);
var from = new EmailAddress(SafeTrim(ConfigurationManager.AppSettings["SendGridEmail"]));
var to = new EmailAddress(emailTo);
var msg = MailHelper.CreateSingleEmail(from, to, subject, string.Empty, body);
try {
var response = await client.SendEmailAsync(msg);
//return response;
return "SUCCESS";
} catch (Exception ex) {
return "ERROR in SendEmailSendGrid(): " + ex.Message;
}
}
And the caller:
var result = utils.SendEmailSendGrid(decodedEmail, "email test", "This is a test email using SendGrid.");
And the error I get every time EVEN THOUGH IT WORKS and the email actually sends and arrives in my inbox:
Object reference not set to an instance of an object.
That error occurs on this line:
var response = await client.SendEmailAsync(msg);
I verified that all my variables are populated as expected - none are null or empty. I am passing an empty string to the plain text param (because I always want HTML contents), but I also tried passing that some content and it made no difference; same error.
A strange thing: this blows up so hard that my catch block is never entered. Instead, as soon as the exception is thrown, this full-screen window comes up in my VS2022:
So it is working and sending the email, but why the heavy crash? What am I doing wrong?
The method is awaitable:
public async Task<string> SendEmailSendGrid(...
Yet, the caller is not awaiting the result:
var result = utils.SendEmailSendGrid(decodedEmail, ...
Either await the result:
var result = await utils.SendEmailSendGrid(decodedEmail, ...
Or, if the invoking method is not an async method:
var result = utils.SendEmailSendGrid(decodedEmail, ...).GetAwaiter().GetResult();
Visual Studio is not breaking inside of your try/catch b/c the exception is in the .NET framework by not awaiting the result. You should be able to resolve that by enabling "just my code" in the visual studio debugger settings (IIRC).
I have such implementation of sending emails with SendGrid. That works fine, but how I can check if an email was sent correctly, of course, I'm not thinking about cases that email address was not correct one but cases like that SendGrid servers were not available or generally, something obviously wrong during email sending
public class EmailSender : IEmailSender
{
public string SendGridKey;
public string SendGridEmail;
public string SendGridName;
public EmailSender()
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
SendGridKey = configuration["EmailCredentials:SendGridKey"];
SendGridEmail = configuration["EmailCredentials:SendGridEmail"];
SendGridName = configuration["EmailCredentials:SendGridName"];
}
public Task SendEmailAsync(string email, string subject, string message)
{
return Execute(SendGridKey, subject, message, email);
}
public Task Execute(string apiKey, string subject, string message, string email)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress(SendGridEmail, SendGridName),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(email));
msg.SetClickTracking(false, false);
return client.SendEmailAsync(msg);
}
}
Take a look at this post maybe you get to know how to check the return value of the mail sending method.
SendGrid SendEmailAsync() - uncatchable exception thrown
SendEmailAsync returns a Task<response> which you can read to determine delivery information (see use cases in the repo docs) while everything in your Excute task could throw an exception if you have the wrong API key, SendGrid is down, or you get some other error (see: troubleshooting in the repo docs). Putting this together:
public async Task Execute(string apiKey, string subject, string message, string email)
{
try {
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress(SendGridEmail, SendGridName),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(email));
msg.SetClickTracking(false, false);
var response=await client.SendEmailAsync(msg);
Console.WriteLine(response.IsSuccessStatusCode
? "Email queued successfully!"
: "Something went wrong!");
}
catch (Exception ex)
{
//Decode the message and log to console (for example)
SendGridErrorResponse errorResponse =
JsonConvert.DeserializeObject<SendGridErrorResponse>(ex.Message);
Console.WriteLine(ex.Message);
}
There's a useful Twilio blog post on the topic: Send Emails with C# and .NET 6 using the SendGrid API
I'm using MailKit to send emails for account confirmation and password reset. These operations work as intended, but now I'm trying to modify the same code to also send email notifications to all registered users but this is where I'm having issues.
I've built a List collection using the following code:
public List<string> UserList {
get {
var allUsers = userManager.Users;
return allUsers.Select(x => x.Email).ToList();
}
}
this collection returns all emails within my AspNetUsers table successfully.
Next I create 3 variables:
var toAddress = UserList;
var subject = "New Asset Added" + " " + model.Name;
var body = model.Name + model.AssetType + model.AssetURL;
When debugging and stepping through the code I do see Count = 2 and then the list of emails in the variable. So far this looks good
After the 3 variables I have this line of code that passes the collected information to the Send method:
_emailSender.Send(toAddress[0], subject, body);
Again, the toAddress[0] when stepping through code shows Count = 2 so I'm assuming the way I have it written is valid.
Once I reach the Send Method code and I check the toAddress variable again, it is now stripped of the Count = 2 and becomes just the first email address in the list which makes sense since I passed the variable with an index of 0. What I really need is to pass all emails not just 1.
If I remove the brackets or leave the brackets empty I get an error:
cannot convert from 'System.Collections.Generic.List<string>' to 'string'
So for now I'm forced to add an index.
My send method seems fairly simple but I do believe my foreach loop might also not be well formulated. Here's my Send Method in it's entirety.
public async void Send(string toAddress, string subject, string body, bool sendAsync = true) {
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
foreach (char toAddresses in toAddress) {
mimeMessage.To.Add(new MailboxAddress(toAddresses)); //I get error saying cannot convert char to string.
}
mimeMessage.Subject = subject;
var bodyBuilder = new MimeKit.BodyBuilder {
HtmlBody = body
};
mimeMessage.Body = bodyBuilder.ToMessageBody();
using (var client = new MailKit.Net.Smtp.SmtpClient()) {
client.Connect(_smtpServer, _smtpPort, _enableSsl);
client.Authenticate(_username, _password); // If using GMail this requires turning on LessSecureApps : https://myaccount.google.com/lesssecureapps
if (sendAsync) {
await client.SendAsync(mimeMessage);
}
else {
client.Send(mimeMessage);
}
client.Disconnect(true);
}
}
My end goal is to use a foreach loop on the mimeMessage.To.Add(new MailboxAddress(toAddresses)); so that everyone can receive an email if there is more than 1 email address, if not it can loop once.
Thanks in advance!
In your method, Send(), you are taking in a string for toAddress and then splitting its characters... that wont work. If you want to to use one or more email addresses, you will need to send in email address(es) separated by a delimiter or as a complete list.
Two ways to go about it.
Change the argument from string to List
change your method to take in a List
public async void Send(List<string> toAddress, string subject, string body, bool sendAsync = true)
{
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
toAddress.ForEach(address => mimeMessage.To.Add(new MailboxAddress(address)));
...
if you use this method, you will need to send in the list as well.. not a single email address string.
List<string> toAddress = new List<string>() { "firstEmail", "Second" ...};
_emailSender.Send(toAddress, subject, body);
// You will not be able to do send in single string
_emailSender.Send("firstemail#only.com", subject, body); //Exception no method found.
Send in a delimited list
Always send in comma separated email addresses and translate those to multiple addresses when adding them to To field of your mimeMessage.
public async void Send(string toAddress, string subject, string body, bool sendAsync = true)
{
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
// HERE -> FOREACH string, not char.
foreach (string toAddresses in toAddress.Split(',')) // Split on ,
{
mimeMessage.To.Add(new MailboxAddress(toAddresses));
}
and you will need to use this method the following way...
List<string> toAddress = new List<string>() {"first", "..."};
_emailSender.Send(string.Join(',',toAddress), subject, body);
In C# I have a web service with an operation result defined as below:
OperationResult<createAccountResponse> CreateAccount(string token, createAccountServiceModel model);
Inside that method I call another method with a signature indicating it is async, like so:
var sendEmailInvite = this.SendExhibitorInviteEmailAsync(new ExhibitorInviteEmailPartialRequest()
{
CompanyId = company.CompanyID,
EventId = event.EventID
});
And inside SendExhibitorInviteEmailAsync I await a method which is also marked as async. Here is that method (snipped for brevity)
public async Task<ExhibitorInviteEmailResponse> SendExhibitorInviteEmailAsync(ExhibitorInviteEmailResolvedRequest request)
{
ExhibitorInviteEmailResponse response = null;
try
{
response = new ExhibitorInviteEmailResponse();
var apiKey = "snip";
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage();
msg.SetFrom(new EmailAddress("noreply#domain.com", "Display name"));
msg.AddTo(new EmailAddress(request.EmailAddress, request.AccountOwnerFirstName));
msg.SetTemplateId("snipped");
\
msg.SetTemplateData(dynamicTemplateData);
await client.SendEmailAsync(msg);
}
catch (Exception ex)
{
response = new ExhibitorInviteEmailResponse
{
Success = false,
Error = true,
ErrorMessage = ex.Message
};
}
return response;
}
If the email is meant to be sent (flag field in the json) then I start working on the email.If no email is meant to be sent, the whole method takes about a second which was what it was before.
The issue I am having is when I run this method from Postman or from C# generated by Postman, it seems the async code for sending the email causes the duration of the request to be 30+ seconds - so it seems like something is not waiting for the email to send? When I run this via a browser it works in 1-2 seconds with no delay.
What is the recommended flow when using Postman and async? Do all internal method's parents have to await as well?
I'm trying to send an email with the Office 365 C# client library. I've successfully performed other operations with it, i.e. getting a folder and getting messages, but am unable to send an email.
I'm using a MailHelper class provided in a Microsoft sample. This is the method:
internal async Task<String> ComposeAndSendMailAsync(string subject,
string bodyContent,
string recipients)
{
// The identifier of the composed and sent message.
string newMessageId = string.Empty;
// Prepare the recipient list
var toRecipients = new List<Recipient>();
string[] splitter = { ";" };
var splitRecipientsString = recipients.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
foreach (string recipient in splitRecipientsString)
{
toRecipients.Add(new Recipient
{
EmailAddress = new EmailAddress
{
Address = recipient.Trim(),
Name = recipient.Trim(),
},
});
}
// Prepare the draft message.
var draft = new Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.HTML,
Content = bodyContent
},
ToRecipients = toRecipients
};
try
{
// Make sure we have a reference to the Outlook Services client.
var outlookClient = await AuthenticationHelper.GetOutlookClientAsync("Mail");
//Send the mail.
await outlookClient.Me.SendMailAsync(draft, true);
return draft.Id;
}
//Catch any exceptions related to invalid OData.
catch (Microsoft.OData.Core.ODataException ode)
{
throw new Exception("We could not send the message: " + ode.Message);
}
catch (Exception e)
{
throw new Exception("We could not send the message: " + e.Message);
}
}
My arguments are not null and seem to be correct. The error I'm getting is: "Cannot read the request body.".
I've made sure my application is registered with the right permissions so I'm at a loss. Does anyone know what's going on with my code?
Try capturing a Fiddler trace of the request and check the Content-Type header.