Email view not found for 'model' in Postal.MVC - asp.net-mvc

I am using Postal.MVC5 in my ASP MVC5 project. Initially i had my smtp configuration in web.config so this piece of code was working just fine and was able to send email successfully.
public async Task<ActionResult>SendEmail(EmployeeViewModel emailModel)
{
string _errorMessage;
emailModel.To = "john#outlook.com";
emailModel.Subject = "Test Subject";
emailModel.Message = "Test Message";
await emailModel.SendAsync();
return Json(new {ErrorMessage = _errorMessage});
}
Now, i need to setup Smtpclient during runtime and followed steps shown in this stackoverflow post: How to Set SMTP Client in POSTAL MVC not in WEB.Config
public async Task<ActionResult>SendEmail(EmployeeEmailViewModel emailModel)
{
string _errorMessage;
emailModel.To = "john#outlook.com";
emailModel.Subject = "Test Subject";
emailModel.Message = "Test Message";
//new code
SmtpClient client = new SmtpClient("smtp.test.com");
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("secretId", "notSecretPassword");
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Port = 111;
client.EnableSsl = true;
Postal.EmailService emailService = new EmailService(new ViewEngineCollection(), () => client);
await emailService.SendAsync(emailModel);
return Json(new {ErrorMessage = _errorMessage});
}
Now this code throws an error something like this:
System.Exception: Email view not found for EmployeeEmailViewModel. Locations searched:
at Postal.EmailViewRenderer.CreateView(String viewName, ControllerContext controllerContext)
at Postal.EmailViewRenderer.Render(Email email, String viewName)
I do have 'EmployeeEmailViewModel' view in ~/Views/Emails/EmployeeEmailViewModel.cshtml .
Any idea why i am getting this error message or how i can resolve it?
Thanks
Sanjeev

Related

Have different version of SendEmailAsync

I am using the default ASP.NET MVC, Identity template... I want to send a confirmation email to my clients.
The default implementation which comes with a new project template, has a Register Method in AccountController.cs
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// 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);
string message = "Please confirm your account by clicking here";
await UserManager.SendEmailAsync(user.Id, "Confirm your account", HttpUtility.UrlEncode(message));
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
There is a call to UserManager.SendEmailAsync, now this method is defined in Microsoft.AspNet.Identity and I don't want to change it.
The actual send email function is in IdentityConfig.cs
public class SendGridEmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass Username here */);
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass confirm url here */);
msg.AddTo(new EmailAddress("info#mycompant.com", "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Now as you see, I am using Sendgrid to send email... so I don't want a message.body to email... I have made some templates and I I want to pass teplate Id with some substituation tags, like username to be replaced in the template.
So I don't want this generic SendAsync method... I want something like
SendGridAsync(SendGridMessage message)
Is it possible to add this method, so I can choose when to call SendAsync and when to call SendGridAsync?
You don't need to use the built in mail service, especially when you want to do something that's a little more complicated.
Define your own messaging service:
public interface IMyMessageService
{
Task SendConfirmationMessage(string confirmUrl, string to)
// define methods for other message types that you want to send
}
public class MyMessageServie : IMyMessageService
{
public async Task SendConfirmationMessage(string confirmUrl, string to)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", confirmUrl);
msg.AddTo(new EmailAddress(to, "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Register IMyMessageService in your DI framework, and inject it into the controller where the emails are being sent from (e.g. the AccountController).
Now, your register action would look like this (assumes I've injected IMyMessageService and have an instance in _myMessageService):
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// 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);
// USE YOUR MESSAGE SERVICE
await _myMessageService.SendConfirmationMessage(callbackUrl, user.Email);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}

How to send email from controller in MVC 4 .net?

I have following code which works fine if I host the website in IIS of my local system. But if I host the website on my Windows Server, it doesn't send mail.
Code of Controller:
[HttpPost]
public ActionResult Index()
{
string tomail = "test#godaddyserver.com";
string SMTPServer = "smtpout.secureserver.net";
string SMTPUserName = "test#godaddyserver.com";
string SMTPPassword = "test123456";
string strMailTitle = "Inquiry Mail";
MailMessage mail = new MailMessage();
SmtpClient SmtpServer = new SmtpClient(SMTPServer);
SmtpServer.Credentials = new NetworkCredential(SMTPUserName, SMTPPassword);
mail.From = new MailAddress(tomail, strMailTitle);
SmtpServer.Port = 25;
mail.To.Add(tomail);
mail.Subject = "Inquiry Mail";
mail.IsBodyHtml = true;
string mailTemplatePath = Server.MapPath("~/template/AdminContactUs.html");
StringBuilder MyStringBuilder = new StringBuilder();
if (System.IO.File.Exists(mailTemplatePath))
MyStringBuilder.Append(System.IO.File.ReadAllText(mailTemplatePath));
mail.Body = MyStringBuilder.ToString();
try
{
SmtpServer.ServicePoint.MaxIdleTime = 1;
SmtpServer.Send(mail);
}
catch (Exception e)
{
}
}
One thing I forgot to add is that it is working fine with Exchange Server email(test#mydomain.com) and SMTP(smtp1.mydomain.com). Current email and SMTP is of Godaddy. However, it is not working with Godaddy, Hostgator or Gmail.
Can anybody please suggest me if I am missing anything?

While Calling Web.api getting 'Method not allowed' error'

While consuming the web.Api i am getting method not allowed(405). i followed all step but issue is still there. But when I test through soapUi it works well. Please help
Web.Api Declaration:
[Route("ForgotPassword")]
[AcceptVerbs( "POST")]
public ForgotPasswordResponse ForgotPassword(string emailId)
{
AccountInfo accountInfo = _manager.GetUserByEmailId(emailId);
if (accountInfo == null)
return new ForgotPasswordResponse
{
Response = "error",
Message = "Email address not found"
};
return new ForgotPasswordResponse
{
Response = "success",
Message = "password reset link set to registered email id"
};
}
Consuming Service call:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://100.7.11.76");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response12 = client.GetAsync("test.Api/api/account/ForgotPassword?EmailId=" + email + "").Result;
if (response12.IsSuccessStatusCode)
{
string responseString = response12.Content.ReadAsStringAsync().Result;
}
}
Your WebAPI controller ForgotPasswordResponse accepts the verb "POST" and your WebAPI client is invoking it as GET. Hence you get 406: Method not allowed response. Either make your controller accept GET verb or invoke the WebAPI using PostAsJsonAsync method instead of GetAsync.
Try to use Authentication Filters [AllowAnonymous]
[AllowAnonymous]
[Route("ForgotPassword")]
[AcceptVerbs( "POST")]
public ForgotPasswordResponse ForgotPassword(string emailId)
{
AccountInfo accountInfo = _manager.GetUserByEmailId(emailId);
if (accountInfo == null)
return new ForgotPasswordResponse
{
Response = "error",
Message = "Email address not found"
};
return new ForgotPasswordResponse
{
Response = "success",
Message = "password reset link set to registered email id"
};
}
Change the Route attribute to [Route("api/account/ForgotPassword")], change from POST to GET and test your method from a REST client like PostMan first and then use it in your application.

GeneratePasswordToken throws odd error in MVC 5 (asp.net Identity) - Lost Password

I am creating a LostPassword function using the code below. When users enter their email and they get a password with link containing the token to reset. In my controller I have the GenerateTokenPassword method (under WebSecurity), but it is throwing this error:
Error: Cannot convert type 'string' to 'int'
Line: var token = WebSecurity.GeneratePasswordResetToken((foundUserName).ToString(), 1440);
When I debug, I get my username in the foundUserName field and it is a string. The 1440 is the timeout on token expiration, and I am supplying an int to begin with. What int is it looking?
Any ideas what this might be?
Thanks,
Sanjeev
// POST: Account/LostPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult LostPassword(LostPasswordModel model)
{
ApplicationUser user;
using (var db = new MyDbContext())
{
var foundUserName = (db.People.Where(p => p.Email == model.Email).FirstOrDefault().UserName);
user = UserManager.FindByName(foundUserName.ToString());
// user = Membership.GetUser(foundUserName);
//Generate password token that will be used in the email link to authenticate user
WebSecurity.InitializeDatabaseConnection("", "System.Data.SqlClient", "AspNetUsers", "Id", "UserName", false);
var token = WebSecurity.GeneratePasswordResetToken((foundUserName).ToString(), 1440);
// Generate the html link sent via email
var code = UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
string resetLink = "<a href='"
+ Url.Action("ResetPassword", "Account", new { rt = token }, "http")
+ "'>Reset Password Link</a>";
//Email stuff
string emailsubject = "Reset your account password.";
string emailbody = "Please click this link to reset your account password: " + resetLink;
string emailfrom = "mymail#mymail.edu";
string emailto = model.Email;
MailMessage message = new MailMessage();
message.To.Add(emailto);
message.From = new MailAddress(emailfrom);
message.Subject = emailsubject;
message.Body = emailbody;
message.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential("mymail", "mypass");
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.Send(message);
return View();
}
}
It would appear that the compiler is interpreting the 1440 value as a string, you could try declaring an explicit int variable for it and passing that instead.
Alternatively, given tokenExpirationInMinutesFromNow is an optional parameter which defaults already to 1440 then you can omit it entirely
var token = WebSecurity.GeneratePasswordResetToken((foundUserName).ToString());

MVC 4 Password Recovery

First I am quite new to MVC and I am trying to implement a password recovery functionality for MVC 4. I am implementing this using this technique posted here: Where to find C# sample code to implement password recovery in ASP .NET MVC2
I understood the way it works however there is missing a helper class that I try to implement right now. I am talking about the class: NotificationsHelper.SendPasswordRetrieval(model.Email, this.ControllerContext);
The RetrievePassword acction controller on the controller has a parameter PasswordRetrievalModel model. I guess that this is a class model that connects to db and implements some properties among theme is a string property called Email. Is this correct?
Than, the NotificationsHelper.SendPasswordRetrieval(model.Email, this.ControllerContext); static class implements this static method SendPasswordRetrievla with 2 paramateres: model.Email that is the string property frrom the PasswordRetrievalModel model class, so this will be the user email to which we will send the email. Than the second parameter is this.ControllerContext. What is the point of this parameter what values will contain that are sent to the SendPasswordRetrieval method?
Than I implemented the class like this:
public static class NotificationsHelper
{
public static bool SendPasswordRetrieval(string emailAddress, ControllerContext ctx)
{
try
{
StringBuilder emailMessage = new StringBuilder();
emailMessage.Append("<br />");
emailMessage.Append("Hello,");
emailMessage.Append("You have requested a password recovery.");
emailMessage.Append("<br />");
emailMessage.Append("Please click the link below to change your password: <br />");
emailMessage.Append("<br />");
emailMessage.Append(string.Format("http://www.example.com/Account/Validate?email={0}&token={1}", emailAddress, "**345982374532453435345**"));
emailMessage.Append("<br />");
MailMessage email = new MailMessage();
email.From = new MailAddress("noreplay#example.com");
email.To.Add(new MailAddress(emailAddress));
email.Subject = "domain.com Password Recovery";
email.Body = emailMessage.ToString();
email.IsBodyHtml = true;
SmtpClient smtpServer = new SmtpClient();
smtpServer.Host = "smtp.gmail.com";
smtpServer.Port = 587;
smtpServer.Credentials = new NetworkCredential("username", "password");
smtpServer.EnableSsl = true;
smtpServer.Send(email);
return true;
}
catch (Exception e)
{
Trace.WriteLine(String.Format("Failure to send email to {0}.", emailAddress));
return false;
}
}
}
In the code above I listed the line where the url is formatted, how do I bring there the token using the code #agarcian provided? Is the token coming from the second parameter ControllerContext? If yes how do i get it from there?
Add new column for usertable name it pwdresetTocket, when user request to reset password insert Guid.NewGuid() in pwdresetTocket field for that user, append the same in callback URL
if you don't want to add column to existing table, you can create a new table and map it to user Table.
Then your method looks like this.
public static bool SendPasswordRetrieval(string emailAddress, ControllerContext ctx)
{
try
{
StringBuilder emailMessage = new StringBuilder();
string token = Guid.NewGuid();
// call to a method that will update the table with token
updateUsertablewithResetTocket(tocken);
emailMessage.Append("<br />");
emailMessage.Append("Hello,");
emailMessage.Append("You have requested a password recovery.");
emailMessage.Append("<br />");
emailMessage.Append("Please click the link below to change your password: <br />");
emailMessage.Append("<br />");
emailMessage.Append(string.Format("http://www.example.com/Account/Validate?email={0}&token={1}", emailAddress, token));
emailMessage.Append("<br />");
MailMessage email = new MailMessage();
email.From = new MailAddress("noreplay#example.com");
email.To.Add(new MailAddress(emailAddress));
email.Subject = "domain.com Password Recovery";
email.Body = emailMessage.ToString();
email.IsBodyHtml = true;
SmtpClient smtpServer = new SmtpClient();
smtpServer.Host = "smtp.gmail.com";
smtpServer.Port = 587;
smtpServer.Credentials = new NetworkCredential("username", "password");
smtpServer.EnableSsl = true;
smtpServer.Send(email);
return true;
}
catch (Exception e)
{
Trace.WriteLine(String.Format("Failure to send email to {0}.", emailAddress));
return false;
}
}
once user resets the password, empty the reset token field

Resources