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
Related
Hi when i use the below code in angular api project my requests are not getting saved and i am gettign this following error. And when i comment the code to send mail everything is working fine
ERROR in console
polyfills POST net::ERR_CONNECTION_RESET
And code to send mail
public async Task SendEmail(string email, string subject, string firstName, string contact)
{
try
{
string message = BuildMessageBody(firstName, email, contact);
using (var client = new SmtpClient())
{
var networkCredential = new NetworkCredential
{
UserName = _configuration["Email:Email"],
Password = _configuration["Email:Password"]
};
client.UseDefaultCredentials = false;
client.Credentials = networkCredential;
client.Host = _configuration["Email:Host"];
client.Port = int.Parse(_configuration["Email:Port"]);
client.EnableSsl = true;
using (var emailMessage = new MailMessage())
{
emailMessage.To.Add(new MailAddress(email));
emailMessage.CC.Add(new MailAddress("my cc adddress"));
emailMessage.From = new MailAddress(_configuration["Email:Email"]);
emailMessage.Subject = subject;
emailMessage.Body = message;
emailMessage.IsBodyHtml = true;
emailMessage.BodyEncoding = System.Text.Encoding.UTF8;
emailMessage.SubjectEncoding = System.Text.Encoding.Default;
emailMessage.ReplyToList.Add(new MailAddress(_configuration["Email:Email"]));
client.SendCompleted += (s, e) => {
client.Dispose();
emailMessage.Dispose();
};
await client.SendMailAsync(emailMessage);
}
}
await Task.CompletedTask;
}
catch (Exception ex)
{
_appLogger.CreateLog("SendEmail - " + ex.Message);
}
}
Any idea why this behaviour???
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");
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
I do not know what I am doing wrong but I want after a user is registered and get an email. I have been following the msdn tutorial and other tutorial and I tried it with different application.
Account Controller
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
user.Email = model.Email;
user.Confirmed = false;
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage(
new System.Net.Mail.MailAddress("21408704#dut4life.ac.za", "Registration"),
new System.Net.Mail.MailAddress(user.Email));
m.Subject = "Confirmation of Email";
m.Body = string.Format("Dear {0} <br/>Thank you please click below: <ahref=\"{1}\" title=\"user Email Confirm\">{1} <\a>", user.UserName, Url.Action
("Confirmed Email", "Accounts", new { Token = user.Id, Email = user.Email }, Request.Url.Scheme));
m.IsBodyHtml = true;
m.BodyEncoding = System.Text.Encoding.UTF8;
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient();
smtp.Host = "pod51014.outlook.com";
smtp.Port = 587;
smtp.Credentials = new System.Net.NetworkCredential("21408704#dut4life.ac.za", "Dut951121");
smtp.EnableSsl = true;
smtp.UseDefaultCredentials = false;
try
{
smtp.Send(m);
}
catch (Exception e)
{
throw e;
}
return RedirectToAction("Confirmed Email", "Accounts", new { Email = user.Email });
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Register model
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
I get this error after it loads for a long time
Server Error in '/' Application.
Source Error:
Line 180: catch (Exception e)
Line 181: {
Line 182: throw e;
Line 183: }
Line 184:
The operation has timed out.
Exception Details: System.Net.Mail.SmtpException: The operation has timed out.
The problem is with your SMTP client. I think you have to set UseDefaultCredentials before Credentials like below:
SmtpClient smtp = new SmtpClient();
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential("21408704#dut4life.ac.za", "Dut951121");
Please let me know if it still doesn't work for you.
Update:
A simple SMTP client would look like below:
using System.Net.Mail;
...
MailMessage mail = new MailMessage("you#yourcompany.com", "user#hotmail.com");
SmtpClient client = new SmtpClient();
client.Port = 25;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredentials("user","pass");
client.Host = "smtp.google.com";
mail.Subject = "this is a test email.";
mail.Body = "this is my test email body";
client.Send(mail);
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.