ASP.NEt Web API 2 SendEmailAsync not sending email? - c#

I have the following code for my register method of my AccountController of my ASP.Net Web-API2 Applicaiton:
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// make sure token code is URLEncoded to make sure any special characters in code are allowed in URI to be created
//code = HttpUtility.UrlEncode(code);
//create the URL to be put into the email
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code = code }));
//create Email
string msgUserId = user.Id;
string msgSubject = "Home Turf Network - Confirm your account";
string msgBody = "Please confirm your Home Turf Network account by clicking here";
//send email
await UserManager.SendEmailAsync(msgUserId, msgSubject, msgBody);
return Ok();
//return CreatedAtRoute("DefaultApi", new { id = user.Id }, user);
}
It creates the user successfully, creates the code, callbackURL and from what I can tell everything that is needed for an email to go out to the registered user. But the Email never goes out....
I have tested the callbackUrl that gets created and it does register the email in the DB successfully after it is put into a browser. If the email would send out it would work perfectly.
I tried putting a breakpoint in my IdentityConfig where my EmailService gets set up and it never gets triggered when I debug the application and I can't figure out why it won't send out the email.
Here is my EmailService in my IdentityConfig.cs:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
//plug in your Email Service here to send an email
MailMessage msg = new MailMessage(ConfigurationManager.AppSettings["mailAccount"], message.Destination, message.Subject, message.Body);
msg.IsBodyHtml = true;
using (SmtpClient client = new SmtpClient("smtp.gmail.com"))
{
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential( ConfigurationManager.AppSettings["mailAccount"], ConfigurationManager.AppSettings["mailPassword"] );
client.Port = 587;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(msg);
}
return Task.FromResult(0);
}
}
Any help tracing this issue out will be much appreciated.

Related

Unable to send mail from bot integrated with slack

I have a bot made in framework v4 using c#.The bot send a email to admin if doesn't able to fetch answer from qna maker.It completely working fine on local emulator, i am able to the mail but when published over slack the bot throw a error.
Here is code
private async Task ProcessSampleQnAAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var results = await _botServices.SampleQnA.GetAnswersAsync(stepContext.Context);
if (results.Any())
{
await stepContext.Context.SendActivityAsync(MessageFactory.Text(results.First().Answer), cancellationToken);
}
else
{
var question = stepContext.Context.Activity.Text;
await stepContext.Context.SendActivityAsync(MessageFactory.Text(_configuration["DefaultAnswer"]), cancellationToken);
string mailbody = "<h4><b>Hi Admin , following question was not answered from bot : </b> </h4>" + question;
Common objCommon = new Common(_configuration);
objCommon.SendEmail(_configuration["EmailSubject_UnAnswerQuestion"], mailbody);
}
}
appsetting.json
"AdminEmailAddress": "****#****.com", //to Email Address
"FromEmailAddress": "******#gmail.com", // From email address
"SMTP_Host": "smtp.gmail.com", // SMTP client Host Name
"SMTP_Port": "587", // SMTP port number
"SMTP_UserName": "****#gmail.com", // email server user name (Email server
network credentials)
"SMTP_Password": "******", // email server password (Email server network
credentials)
"EmailSubject_UnAnswerQuestion": "Question whose answer not found", //
Subject string for un- answere question email.
"DefaultAnswer": "Sorry, could not find an answer in the Q and A system.", //
default answere if answere not found in QnA.
"DelayTimeInSeconds": "60" // Feed back dely time in seconds.
Common logic of smtp
public class Common
{
private readonly IConfiguration _configuration;
public Common(IConfiguration configuration)
{
_configuration = configuration;
}
public bool SendEmail(string subject, string mailbody)
{
string to = _configuration["AdminEmailAddress"]; //To address
string from = _configuration["FromEmailAddress"]; //From address
MailMessage message = new MailMessage(from, to);
message.Subject = subject;
message.Body = mailbody;
message.BodyEncoding = Encoding.UTF8;
message.IsBodyHtml = true;
SmtpClient client = new SmtpClient(_configuration["SMTP_Host"],
int.Parse(_configuration["SMTP_Port"])); //Gmail smtp
System.Net.NetworkCredential basicCredential1 = new
System.Net.NetworkCredential(_configuration["SMTP_UserName"],
_configuration["SMTP_Password"]);
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = basicCredential1;
try
{
client.Send(message);
return true;
}catch (Exception ex)
{
throw ex;
}}

How to return view while waiting for await function in MVC

I work with await function for sending an email. Is there have any solutions how to display page or return view() while waiting for await function complete.
Here is my code:
using (var smtp = new SmtpClient())
{
var credential = new NetworkCredential
{
UserName = "email#gmail.com",
Password = "paswordEmail"
};
smtp.Credentials = credential;
smtp.Host = "smtp-mail.outlook.com";
smtp.Port = 587;
smtp.EnableSsl = true;
await smtp.SendMailAsync(message); //Here is my await function for sending an email
return RedirectToAction("ThankYou"); //This thank you page. I want to display this html page without waiting for await complete
}
You can wrap the mail code in a Task.Run and not await it.
Task.Run(async () => {
using (var smtp = new SmtpClient()) {
var credential = new NetworkCredential {
UserName = "email#gmail.com",
Password = "paswordEmail"
};
smtp.Credentials = credential;
smtp.Host = "smtp-mail.outlook.com";
smtp.Port = 587;
smtp.EnableSsl = true;
await smtp.SendMailAsync(message); //Here is my await function for sending an email
}
});
return RedirectToAction("ThankYou");
ASP.NET has it's own facility to execute background work: HostingEnvironment.QueueBackgroundWorkItem Method.
Just post your work there:
HostingEnvironment.QueueBackgroundWorkItem(
async () =>
{
using (var smtp = new SmtpClient
{
Host = "smtp-mail.outlook.com",
Port = 587,
EnableSsl = true,
Credentials = new NetworkCredential
{
UserName = "email#gmail.com",
Password = "paswordEmail",
},
})
{
await smtp.SendMailAsync(message); //Here is my await function for sending an email
}
});
return RedirectToAction("ThankYou");

MVC Azure SendGrid

I have a controller action method when triggered post data to the ForgotPassword method:
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
web.config file
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="SendGridUsername" value="XXXXXXXXXXXXXXXXXXXXXX" />
<add key="SendGridPassword" value="XXXXXXXXXXXXXX" />
<add key="SendGridApiKey" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
</appSettings>
My IdentityConfig file looks like this:
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
await configSendGridasync(message);
}
// Use NuGet to install SendGrid (Basic C# client lib)
private async Task configSendGridasync(IdentityMessage message)
{
var myMessage = new SendGridMessage();
myMessage.AddTo(message.Destination);
myMessage.From = new System.Net.Mail.MailAddress(
"Joe#contoso.com", "Joe S.");
myMessage.Subject = message.Subject;
myMessage.Text = message.Body;
myMessage.Html = message.Body;
var credentials = new NetworkCredential(
ConfigurationManager.AppSettings["SendGridUsername"],
ConfigurationManager.AppSettings["SendGridPassword"]
);
// Create a Web transport for sending email.
var transportWeb = new Web(credentials);
// Send the email.
if (transportWeb != null)
{
await transportWeb.DeliverAsync(myMessage);
}
else
{
Trace.TraceError("Failed to create Web transport.");
await Task.FromResult(0);
}
}
}
However no email is sent , what am I doing wrong and how can I fix this as I have followed the instructions from Rick Andersons post on msdn.
You are using an outdated version of sendgrid C# SDK which points to V2 api. The current API version is V3. The document which you are following is not updated . I am currently in progress to update the document. You need to add the below namespace in your service -
using SendGrid;
using SendGrid.Helpers.Mail; //optional if you want to use the MailHelper class
And then use below code in your configSendGridasync method -
private async Task configSendGridasync(IdentityMessage message)
{
var apiKey = Convert.ToString(ConfigurationManager.AppSettings["SendGridApiKey"]);
var client = new SendGridClient(apiKey);
var myMessage = new SendGridMessage();
myMessage.AddTo(new EmailAddress(message.Destination));
myMessage.SetFrom(new EmailAddress("Joe#contoso.com", "Joe S."));
myMessage.SetSubject(message.Subject);
myMessage.AddContent(MimeType.Text, message.Body);
myMessage.AddContent(MimeType.Html, message.Body);
try
{
var response = await client.SendEmailAsync(msg);
}
catch(Exception err)
{
Trace.TraceError("Failed to create Web transport: ."+err.message);
await Task.FromResult(0);
}
}
You need to install Sendgrid package from nuget using the below command before writing the code -
Install-Package Sendgrid -Version 9.10.0
The full code is like below -
using SendGrid;
using SendGrid.Helpers.Mail;
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
await configSendGridasync(message);
}
// Use NuGet to install SendGrid (Basic C# client lib)
private async Task configSendGridasync(IdentityMessage message)
{
var apiKey = Convert.ToString(ConfigurationManager.AppSettings["SendGridApiKey"]);
var client = new SendGridClient(apiKey);
var myMessage = new SendGridMessage();
myMessage.AddTo(new EmailAddress(message.Destination));
myMessage.SetFrom(new EmailAddress("Joe#contoso.com", "Joe S."));
myMessage.SetSubject(message.Subject);
myMessage.AddContent(MimeType.Text, message.Body);
myMessage.AddContent(MimeType.Html, message.Body);
try
{
var response = await client.SendEmailAsync(msg);
}
catch(Exception err)
{
Trace.TraceError("Failed to create Web transport: ."+err.message);
await Task.FromResult(0);
}
}
}
Here is a link to example code :
https://github.com/sendgrid/sendgrid-csharp/blob/master/USE_CASES.md

Why am I not getting a password reset email?

In the first 8 minutes of this tutorial, the developer tells you to uncomment the code in the forgotpassword() in the account controller, the email confirmation in the if, and finally the link to get the forgot password page on the login screen. He then tells you to write in the following code in your Identity config.
using System.Net.Mail;
public Task SendAsync(IdentityMessage message)
{
//Emails will be sent from this address
var from = "someusername#gmail.com";
var pass = "somepassword";
//setting up SMTP client
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential(from, pass);
client.EnableSsl = false;
//Create Email
var mail = new MailMessage(from, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
mail.IsBodyHtml = true;
//Send email
return client.SendMailAsync(mail);
// Plug in your email service here to send an email.
return Task.FromResult(0);
}
My project builds as it does in the tutorial however, he is able to receive an email in the tutorial but I do not. I double and triple checked my username and password. What did I miss?

UserManager.SendEmailAsync hangs

I have a custom user manager with a custom EmailService. I'm calling the UserManager.SendEmailAsync() method in the AccountController, and it just hangs. I even tried to use it with invalid SMTP hostname, then an exception occurs and in debug I can see it goes into the catch block, but regardless the return View(model) statement, it just "hangs" in the browser and keeps on loading forever.
Any ideas?
ApplicationUserManager constructor:
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
EmailService = new EmailService();
}
EmailService:
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
// Credentials:
string smtpServer = ConfigurationManager.AppSettings["EmailSmtpServer"];
int smtpPort = int.Parse(ConfigurationManager.AppSettings["EmailSmtpPort"]);
bool enableSsl = bool.Parse(ConfigurationManager.AppSettings["EmailEnableSSL"]);
string smtpUsername = ConfigurationManager.AppSettings["EmailSmtpUsername"];
string smtpPassword = ConfigurationManager.AppSettings["EmailSmtpPassword"];
string sentFrom = ConfigurationManager.AppSettings["EmailSentFrom"];
// Configure the client:
var client = new SmtpClient(smtpServer, Convert.ToInt32(587));
client.Port = smtpPort;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.EnableSsl = enableSsl;
// Create the credentials:
var credentials = new NetworkCredential(smtpUsername, smtpPassword);
client.Credentials = credentials;
// Create the message:
var mail = new System.Net.Mail.MailMessage(sentFrom, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
// Send:
await client.SendMailAsync(mail);
}
}
ForgotPassword method in AccountController
//
// POST: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
// Don't check confirmation status for now
//if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
if (user == null)
{
ModelState.AddModelError("", "The user either does not exist or is not confirmed.");
return View();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
try
{
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
return View(model);
}
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
This Works for me
ApplicationUserManager constructor:
public AppUserManager(IUserStore<AppUser> store)
: base(store)
{
this.UserTokenProvider = new TotpSecurityStampBasedTokenProvider<AppUser, string>();
this.EmailService = new EmailService();
}
EmailService:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Credentials:
var credentialUserName = ConfigurationManager.AppSettings["emailFrom"];
var sentFrom = ConfigurationManager.AppSettings["emailFrom"];
var pwd = ConfigurationManager.AppSettings["emailPassword"];
// Configure the client:
System.Net.Mail.SmtpClient client =
new System.Net.Mail.SmtpClient("smtp-mail.outlook.com");
client.Port = 587;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
// Create the credentials:
System.Net.NetworkCredential credentials =
new System.Net.NetworkCredential(credentialUserName, pwd);
client.EnableSsl = true;
client.Credentials = credentials;
// Create the message:
var mail =
new System.Net.Mail.MailMessage(sentFrom, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
// Send:
return client.SendMailAsync(mail);
}
}
IMPORTANT If you are using external mail provider you should revise your external applications configurations for example:
gmail : Allowing less secure apps to access your account
ForgotPassword method in AccountController
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RecoveryPassword(LoginInfoModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account",
new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password",
"Reinicia tu contraseƱa clicando : aqui");
return View("ForgotPasswordConfirmation");
}
// If we got this far, something failed, redisplay form
return View(model);
}
And finally I see my e-mail on my mailbox

Categories