Sending a clickable deep link in email in a web api project - c#

I am trying to invoke a deep link that would be sent to the user in an email.
Its a typical forgot password scenario however instead of resetting the password via a web link , the user would do so in an android application.
Here is how i generate the email .
[HttpPost]
[AllowAnonymous]
[Route("ForgotPassword")]
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordBindingModel model)
{
if (ModelState.IsValid)
{
var user = await AppUserManager.FindByEmailAsync(model.Email);
if (user == null || !(await AppUserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return Ok();
}
// Send an email with this link
string code = await AppUserManager.GeneratePasswordResetTokenAsync(user.Id);
//var callbackUrl = new Uri(Url.Link("ResetPasswordRoute", new { user.Id, code }));
var callbackIntent = "intent://forgotpassword?code="+code+"#Intent;scheme=challengehunt;package=com.seed.challengehunt;end";
await AppUserManager.SendEmailAsync(user.Id, "Reset Password", "This would only work if you are seeing this email in an android device. Please reset your password by clicking here");
return Ok();
}
return BadRequest(ModelState);
}
This is my email service attached to the user manager
private async Task ConfigureGmailAsync(IdentityMessage message)
{
// Mail message
var mail = new MailMessage()
{
From = new MailAddress("xyz#xyz.com", "Admin"),
Subject = message.Subject,
Body = message.Body,
IsBodyHtml=true
};
// Credentials
var credentials = new NetworkCredential("admin#xyz.com", "xyz");
mail.To.Add(message.Destination);
// Smtp client
var client = new SmtpClient()
{
Port = 8889,
UseDefaultCredentials = false,
Host = "mail.domain.com",
EnableSsl = false,
Credentials = credentials
};
// Send it...
await client.SendMailAsync(mail);
}
This is the email i receive
As you can see the link is not clickable.
Any hints?

Related

Mail confirmation issue in ASP.NET Core Mvc

I am working on a project which is in ASP.NET Core.
In this project users have to confirm their mail before using their panel. I have written this part of code but there is a problem.
When I debug project and I get the confirmation link, copy it and
paste it to browser, mail confirmation goes successful
but
when I send confirmation Url by email to user's mail and user clicks on it to redirect to my website confirmation fails.
I don't understand the issue because it's weird. I have hard coded some part to test it but nothing changed.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
try
{
if (ModelState.IsValid)
{
if (model.ReferralCode != null)
{
var tmpUser = userManager.Users.FirstOrDefault(f => f.IntroductionCode == model.ReferralCode);
if(tmpUser == null)
{
return Json(new { result = "error", target = "register", message = $"No user found with this({model.ReferralCode}) referral code" });
}
}
var user = new ApplicationUser
{
Id = Guid.NewGuid().ToString(),
FullName = model.FullName,
Email = model.Email,
UserName = model.Email,
Balance = 0,
ReferralCode = model.ReferralCode,
IntroductionCode = new Random().RandomString(16),
IsVerified = false
};
var signUpResut = await userManager.CreateAsync(user, model.Password);
if (signUpResut == IdentityResult.Success)
{
var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
var emailActivationUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, verifyToken = token });
new MailHelper(_logger).SendConfirmationEmail(user.FullName,user.Id, user.Email, token);
_logger.Log(LogLevel.Information, $"User {model.Email} Registered Successfully.");
return Json(new { result = "success", target = "register", message = "You have successfully registered. Check your mail to activate account." });
}
return Json(new { result = "error", target = "register", message = "Something went wrong in server side." });
}
return Json(new { result = "error", target = "register", message = "Something went wrong in server side." });
}
catch (Exception exc)
{
_logger.Log(LogLevel.Critical, $"Failed Registeration : {exc.Message}");
return Json(new { result = "error", target = "register", message = "Something went wrong in server side." });
}
}
here is mail sender code
public bool SendConfirmationEmail(string name, string id, string email, string confirmationToken)
{
try
{
var mailMessage = new MimeMessage();
mailMessage.From.Add(new MailboxAddress("***", "***"));
mailMessage.To.Add(new MailboxAddress(name, email));
mailMessage.Subject = "subject";
var configurationUrl = $"https://localhost:44323/Account/ConfirmEmail?userId={id}&verifyToken={confirmationToken}";
mailMessage.Body = MailBodyMaker($"Click here", "Click here");
using (var smtpClient = new SmtpClient())
{
smtpClient.Connect("smtp.gmail.com", 465, true);
smtpClient.Authenticate("***", "****");
smtpClient.Send(mailMessage);
smtpClient.Disconnect(true);
}
return true;
}
catch(Exception exc)
{
_logger.Log(LogLevel.Critical, $"Email sending finished with exception ${exc.Message}");
return false;
}
}
The confirmation link looks like below in debug mode
https://localhost:44323/Account/ConfirmEmail?userId=9bb1a751-813b-48d2-a44c-74fd32a2db9a&verifyToken=CfDJ8A%2FFQtr0XBRFinX98FbsJc5LpPXqjstNllYq%2Br7kr6BHFfA7lBINCCoviE0nqJ6EQc1sJ7RW87jNsaR3fEkEbKoOhemFE62GCrTfn9gEizWV99lZhMrLxJPzGm1u6j3x%2FARoBqVuCVpp34ki0OZM%2BEJi31hNbwyowZ4YwoOnKjMqAOdu2bVG46WfXZBRG9AiOaFNTy326ijQmaTVDNSBl8lQR4gBWkmmRAdkcdFfOasLHD24wyUjmqgkOM2yTJ19Dw%3D%3D
and it looks like below in email body
https://localhost:44323/Account/ConfirmEmail?userId=9bb1a751-813b-48d2-a44c-74fd32a2db9a&verifyToken=CfDJ8A/FQtr0XBRFinX98FbsJc5LpPXqjstNllYq+r7kr6BHFfA7lBINCCoviE0nqJ6EQc1sJ7RW87jNsaR3fEkEbKoOhemFE62GCrTfn9gEizWV99lZhMrLxJPzGm1u6j3x/ARoBqVuCVpp34ki0OZM+EJi31hNbwyowZ4YwoOnKjMqAOdu2bVG46WfXZBRG9AiOaFNTy326ijQmaTVDNSBl8lQR4gBWkmmRAdkcdFfOasLHD24wyUjmqgkOM2yTJ19Dw==
Certain characters must be escaped in url, and your verification token contains such characters, however you put it as is into your url here:
var configurationUrl = $"https://localhost:44323/Account/ConfirmEmail?userId={id}&verifyToken={confirmationToken}";
To escape them - use Uri.EscapeDataString:
var configurationUrl = $"https://localhost:44323/Account/ConfirmEmail?userId={Uri.EscapeDataString(id)}&verifyToken={Uri.EscapeDataString(confirmationToken)}";

Xamarin Firebase Sending Email Verification

good day how to send an email verification on Xamarin after you register an account I'm using this code but in sendEmailVerification it said FirebaseAuth does not define sendEmailVerification
how can I fix this?
private void LoginUser(string email, string password){
if (input_password.Text == reinput_password.Text){
auth.CreateUserWithEmailAndPassword(email, password)
.AddOnCompleteListener(this, this);
auth.sendEmailVerification(email)
.AddOnCompleteListener(this, this);
}
}
SendEmailVerification(Async) is a method on an FirebaseUser instance:
Example (using Xamarin async wrappers):
auth = FirebaseAuth.Instance;
using (var authResult = await auth.CreateUserWithEmailAndPasswordAsync("so#sushi.com", "stackoverflow"))
using (var user = authResult.User)
using (var actionCode = ActionCodeSettings.NewBuilder().SetAndroidPackageName(PackageName,true, "0").Build())
{
await user.SendEmailVerificationAsync(actionCode);
}
my code works but there is something wrong IsEmailVerified always false
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(webapi));
var auth = await authProvider.SignInWithEmailAndPasswordAsync(emailtxt.Text, passwordtxt.Text);
string gettoken = auth.FirebaseToken;
var content = await auth.GetFreshAuthAsync();
var serializedcontnet = JsonConvert.SerializeObject(content);
Preferences.Set("MyFirebaseRefreshToken", serializedcontnet);
if(content.User.IsEmailVerified == false)
{
var action = await App.Current.MainPage.DisplayAlert("Alert", "Your Email not activated,Do You want to Send Activation Code again?!", "Yes","No");
if(action)
{
await authProvider.SendEmailVerificationAsync(gettoken);
}
}

Email Confirmation: UserManager.ConfirmEmailAsync Error : Name cannot be null or empty

I am trying to write code for email confirmation during email registration for my website. I have a bit customized User model which is similar to regular User code.
The code for sending the email confirmation is in within the Register action:
userService.InsertUser(user);
var appuser = new ApplicationUser(user); //{ UserName = model.Email, Email = model.Email };
appuser.UserName = model.Email;
//var result = await UserManager.CreateAsync(appuser, model.Password);
//if (result.Succeeded)
//{
// await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// // 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(appuser.Id);
//string htmlcode = HttpUtility.UrlEncode(code);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = appuser.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(appuser.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("RegisterComplete");
From the code, I got the callbackurl which is like http://localhost:63599/Account/ConfirmEmail?userId=22&code=C3mfUtYqGzVCsrCnE5VDzC0wfsbgP6lMSVgqFk25kym3uGh0%2B%2Bltqyh0VRim1ulbwSRHBzAgUCJ1WceipbRcErddmNJqzkksZN50QO%2FqTRprpgKcW19wX33QtftwCh7zUz%2B01aghCdg8jZ8Ff%2FNVfRvbjyIW0wavN0Ueq3xl6jBmrv%2BrnbtuKLJO%2BuFE2zHF
When I type the code into the browser, it will run the ConfirmEmail action from AccountController:
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
//if (result.Succeeded)
//{
// UserService userService = new UserService();
// long uid = long.Parse(userId);
// User user = userService.GetBy(u => u.UserID == uid).FirstOrDefault();
// user.IsVerified = true;
// userService.Update(user);
//}
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
But the result.Succeeded is false. And result.Error[0] : Name cannot be null or empty.
I cannot find anymore information about this error in this context and therefore I am quite stuck.
If I change the confirmation code, I will get result.Error[0]: Invalid token, this made me think that at least my token has been correct. But I don't what this error is complaining about.
Any help/pointers will be appreciated.

Identity using SendGrid v3 to send transactional template as confirmation email

I'm new to asp.net mvc Identity and SendGrid but would really like to use the functionality of both of them.
I would like to let the user sign up using identity registration form and then use SendGrid v3 to send a template (built in my SendGrid account) as the account registration confirmation email. I've created a Transactional template and have an Api Key.
I have enabled email confirmation in identity:
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
I have then set up my sendGrid apiKey and account credentials in the app settings of my web.config so I can use them in my code.
<appSettings>
<add key="SendGridUsername" value="xxxxxxx" />
<add key="SendGridPassword" value="xxxxxxx" />
<add key="SendGridApiKey" value="xxxxxxxxxxxxxxxxxxxxxxxx" />
</appSettings>
I have added this to my EmailService in the IdentityConfig.cs but i'm stuck on where to go from here:
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
// Plug in your email service here to send an email.
var apiKey = WebConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var from = new EmailAddress("me#us.com", "Me");
var subject = message.Subject;
var to = new EmailAddress(message.Destination);
var email = MailHelper.CreateSingleEmail(from, to, subject, "", message.Body);
await client.SendEmailAsync(email);
}
}
I've also read the following but cannot understand where to implement it:
https://sendgrid.com/docs/API_Reference/Web_API_v3/Transactional_Templates/smtpapi.html
{
"filters": {
"templates": {
"settings": {
"enable": 1,
"template_id": "5997fcf6-2b9f-484d-acd5-7e9a99f0dc1f"
}
}
}
}
Any help on this would be awesome as i'm just not sure where to go from here.
Thanks
You can send Transactional Templates in your emails using this code below:
var apiKey = AppConstants.JuketserSendGridKey;
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage();
msg.SetFrom(new EmailAddress("admin#jukester.com", "Jukester"));
//msg.SetSubject("I'm replacing the subject tag");
msg.AddTo(new EmailAddress(model.EmailTo));
//msg.AddContent(MimeType.Text, "I'm replacing the <strong>body tag</strong>");
msg.SetTemplateId("Your TemplateId here");
var response = await client.SendEmailAsync(msg);
var status = response.StatusCode.ToString();
Edit For Your Other question:
For Email confirmation scenario, you will have to send email to the registered email when a user signs up. Create a verification token and save it in database. That email will contain some link or a button in it. This link or button will have that verification token with it. Once user clicks that link/button, a webapi or an action method will be called in the project, there you will verify the verification code and then update the status of EmailConfirmed in the database.
Following are some code snippets that i have done, they might be of help to you.
The following code creates a verification code and updates the user record in database.
var encryptedToken = Utility.Crypt(user.Email);
var updateStatus = await UpdateVerificationCode(userToAdd, encryptedToken);
The following then passes this verification code to the data that needs to be sent in the email. "paramList" is a list of data.
if (updateStatus)
{
paramList.Add(encryptedToken);
var emailModel = Utility.CreateEmailModel(user.Email, paramList, AppConstants.RegistrationTemplateId, (int)EmailType.Register);
await Helper.SendEmail(emailModel);
}
Now this code, will be attached in the link or button in the email sent to user for email verification. When user clicks that link/button then following web api action method for email verification is called.
public async Task<GenericResponse> ConfirmEmail(SetPasswordBindingModel model)
{
var response = new GenericResponse();
if (model != null)
{
try
{
var user = await _aspNetUserService.GetByEmail(model.Email);
if (user != null)
{
if (!string.IsNullOrEmpty(model.VerificationCode))
{
//if time difference is less than 5 minutes then proceed
var originalKey = Utility.Decrypt(model.VerificationCode);
if (user.Email == originalKey)
{
var emailConfirmationCode = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var result = await UserManager.ConfirmEmailAsync(user.Id, emailConfirmationCode);
if (result.Succeeded)
{
var status = await _aspNetUserService.ResetVerificationCode(model.Email);
if (status)
{
response.Message = AppConstants.EmailConfirmed;
response.IsSuccess = true;
}
}
else
{
response.Message = AppConstants.Error;
response.IsSuccess = false;
}
}
else
{
response.Message = AppConstants.InvalidVerificationCode;
response.IsSuccess = false;
}
}
else
{
response.Message = AppConstants.InvalidVerificationCode;
response.IsSuccess = false;
}
}
else
{
response.Message = AppConstants.NoUserFound;
response.IsSuccess = false;
}
}
catch (Exception ex)
{
//response.Message = AppConstants.Error;
response.Message = ex.Message;
}
}
return response;
}
You can take a look at it, and use it if it helps your needs. Thanks

Get user's email address based on his userID .net identity

I have the following function that re-generate a confirmation email (to complete registration) in case of an expired link.
[AllowAnonymous]
[HttpGet]
[Route("ResendConfirmationEmail")]
public async Task<IHttpActionResult> ResendConfirmationEmail(string userId = "")
{
if (string.IsNullOrWhiteSpace(userId))
{
ModelState.AddModelError("", "User Id is required");
return BadRequest(ModelState);
}
if (userId.GetHashCode() != null)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(userId);
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId, code = code }));
string subject = "Please confirm your account";
string body = "Please confirm your account by clicking this : link";
SendEmail(?????, callbackUrl, subject, body);
}
return Ok();
}
How can I get the email of the user from the webUsers table based on his userid?
You can fetch user from database using UserManager's FindByIdAsync and then get the email
var user = await UserManager.FindByIdAsync(userId);
var email = user.Email;

Categories