I am trying to create EmailTemplates. I have been able to write the controller codes and also created a .txt file in a folder but when the mail is been sent, the users receive it as a HTML code.
Controller code
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email,
Firstname = model.Firstname, Surname = model.Surname, Gender = model.Gender};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
string body = string.Empty;
var root = AppDomain.CurrentDomain.BaseDirectory; using (var reader = new System.IO.StreamReader(root + #"/EmailTemplates/ConfirmAccount.txt"))
{
string readFile = reader.ReadToEnd();
string StrContent = string.Empty;
StrContent = readFile;
//Assing the field values in the template
StrContent = StrContent.Replace("[Firstname]", user.Firstname);
StrContent = StrContent.Replace("[Surname]", user.Surname);
StrContent = StrContent.Replace("[Code]", callbackUrl);
StrContent = StrContent.Replace("[Year]", DateTime.Now.Year.ToString());
body = StrContent.ToString();
}
await UserManager.SendEmailAsync(user.Id, "Confirm Your Account", body);
return View("DisplayEmail");
}
AddErrors(result);
}
return View(model);
}
Below is the .txt file content
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8">
</head>
<body>
<p>Dear [Firstname] [Surname],</p>
<p>Kindly Confirm your Email by clicking the link below</p>
<p>[Code]</p>
</body>
The output is in form of a HTML.
The better way to send HTML formatted Email your code will be in "ConfirmAccount.htm"
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8">
</head>
<body>
<p>Dear [Firstname] [Surname],</p>
<p>Kindly Confirm your Email by clicking the link below</p>
<p>[Code]</p>
</body>
Read HTML file Using System.IO.File.ReadAllText. get all HTML code in string variable.
string Body = System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath("EmailTemplates/ConfirmAccount.htm"));
Replace a Particular string with your custom value.
Body = Body.Replace("[Firstname]", user.Firstname);
Call SendEmail(string Body) Function and do a procedure to send an email.
Replace the Session email and Configuration app settings with your ones.
public static void SendEmail(string Body)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(Session["Email"].Tostring());
message.To.Add(ConfigurationSettings.AppSettings["RequesEmail"].ToString());
message.Subject = "Request from " + SessionFactory.CurrentCompany.CompanyName + " to add a new supplier";
message.IsBodyHtml = true;
message.Body = Body;
SmtpClient smtpClient = new SmtpClient();
smtpClient.UseDefaultCredentials = true;
smtpClient.Host = ConfigurationSettings.AppSettings["SMTP"].ToString();
smtpClient.Port = Convert.ToInt32(ConfigurationSettings.AppSettings["PORT"].ToString());
smtpClient.EnableSsl = true;
smtpClient.Credentials = new System.Net.NetworkCredential(ConfigurationSettings.AppSettings["USERNAME"].ToString(), ConfigurationSettings.AppSettings["PASSWORD"].ToString());
smtpClient.Send(message);
}
You can check out in message.IsBodyHtml = true SendEmailAsyn Method
Related
I'm sending email via asp.net Core 2.0 like this tutorial, so I have something like this into my controller
SmtpClient client = new SmtpClient("mysmtpserver");
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("username", "password");
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("whoever#me.com");
mailMessage.To.Add("receiver#me.com");
mailMessage.Body = "body";
mailMessage.Subject = "subject";
client.Send(mailMessage);
and it works, but I want to do it less generic. Like sending code to class and call it from controller. For example in class I want to use variables instead static content like
mailMessage.Body = "body";
Instead this I want to use something like:
var body;
mailMessage.Body = body;
So into controller have ability to change that content. How can I achieve that? Regards
In your controller, add a private function called SendEmail something like
private bool SendEmail(string mail_to, string mail_subject, mail_body)
{
bool result = false;
try
{
SmtpClient client = new SmtpClient("mysmtpserver");
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("username", "password");
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("whoever#me.com");
mailMessage.To.Add(mail_to);
mailMessage.Body = mail_body;
mailMessage.Subject = mail_subject;
client.Send(mailMessage);
result = true;
}
catch(Exception ex){ result = false; }
return result;
}
Use it in your controller
string mailBody = "Anything can be in the body\n. Mail contents.";
string subject = "Mail Subject";
string mailTo = "someone#someone.com"
SendEmail(mailTo, subject, mailBody)
I am developping a Asp.Net MVC 5 project. I have this controller that save data from a user.Now i wanna sedn an email to that user after i have saved the data notifying him/her with the password we auto-generated.
Here is my create action
[HttpPost]
public ActionResult Create(TeacherViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View("Create", viewModel);
}
var teacher = new Teacher
{
Identifier = viewModel.Identifier,
Name = viewModel.Name,
Surname = viewModel.Surname,
Email = viewModel.Email,
PhoneNumber = viewModel.PhoneNumber,
Ville = viewModel.Ville,
Block = viewModel.Block,
Password = viewModel.Password
};
_context.Teachers.Add(teacher);
_context.SaveChanges();
return RedireToAction("Index","Home");
Save data and send email to the user with their password and email
As you need to send an email and password in email after save the data, please refere below mentioned code as per your requirement, Hope it helps you.
[HttpPost]
public ActionResult Create(TeacherViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View("Create", viewModel);
}
var teacher = new Teacher
{
Identifier = viewModel.Identifier,
Name = viewModel.Name,
Surname = viewModel.Surname,
Email = viewModel.Email,
PhoneNumber = viewModel.PhoneNumber,
Ville = viewModel.Ville,
Block = viewModel.Block,
Password = viewModel.Password
};
_context.Teachers.Add(teacher);
_context.SaveChanges();
// For send an email
string mailfrom = "sender mail", mailTo = teacher.Email, //"receiver mail",
subject = "Subject Line", filepath = "", htmlbody = "";
filepath = Server.MapPath("~/path_for_email_template/template.html");
htmlbody = System.IO.File.ReadAllText(filepath);
/* you can replace some dynamic contents from body as per your requirements like as name, email but for that you need to all the variable with unique pattern so you can easily replace them, ex: %name% */
htmlbody = htmlbody.Replace("%name%", teacher.Name)
.Replace("%password%", teacher.Password) // as you want to send a password inside mail.
.Replace("%email%", teacher.Email);
try
{
// you need to include
// using System.Net;
// using System.Net.Mail;
SmtpClient client = new SmtpClient("host");
client.Port = 25;// int port number
client.Credentials = new NetworkCredential("Sender_UserName", "Sender_password");
client.EnableSsl = false;//true if ssl required
MailMessage msg = new MailMessage();
msg.To.Add(mailTo);
msg.From = new MailAddress(mailfrom.Trim());
msg.Subject = subject;
msg.Body = htmlbody;
msg.IsBodyHtml = true;
client.Send(msg);
}
catch (SmtpException ex) { throw (ex); }
return RedireToAction("Index", "Home");
}
I am sending a link using email to create password but while sending link in an email i have attach my Activation Code also to display with link but it is not displaying when i click on link though in debugging i'm getting the link with Activation Code. Below is my code to add link in Body section
body+=#"<br /><a href='http://localhost:49234/Index.aspx?ActivationCode='"+objUserDetailsBE.ActivationCode+"'>Create a login to account</a>";
I am getting only till http://localhost:49234/Index.aspx?ActivationCode= in browser after click on the link Please let me know where i am doing wrong.
Adding code as per in comments:
string emailAddress = txtEmailAddress.Text;
string subject = "Login Credentials For Nth Star";
string body = string.Format("Hello,");
body+=#"<br /><a href='http://localhost:49234/Index.aspx?ActivationCode='"+objUserDetailsBE.ActivationCode+"'>Create a login to account</a>";
Email.SendMail(objemail, emailAddress, subject, body, "");
and below is my 'SendMail' method
public static bool SendMail(EmailConfigurationBE objEmailConfig, string toEmailAddresses, string subject, string body, string mailAttachments)
{
char[] splitter = { ';' };
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(objEmailConfig.Email);
mailMessage.Subject = subject;
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
mailMessage.Priority = MailPriority.High;
string[] multi = toEmailAddresses.Split(';');
string[] multipath = mailAttachments.Split(';');
foreach (string MultiemailId in multi)
{
mailMessage.To.Add(new MailAddress(MultiemailId));
}
if (mailMessage.To.Count > 0)
{
//Adding Multiple Attachments
if (mailAttachments != "")
{
foreach (string Multipath1 in multipath)
{
Attachment attachFile = new Attachment(Multipath1);
mailMessage.Attachments.Add(attachFile);
}
}
SmtpClient smtpClient = new SmtpClient();
try
{
smtpClient.Host = objEmailConfig.SMTPServer;
smtpClient.EnableSsl = EnableSsl;
System.Net.NetworkCredential NetworkCred = new System.Net.NetworkCredential();
NetworkCred.UserName = objEmailConfig.Email;
NetworkCred.Password =objEmailConfig.Password;
smtpClient.UseDefaultCredentials = true;
smtpClient.Credentials = NetworkCred;
smtpClient.Port =Convert.ToInt32(objEmailConfig.PortNumber);
smtpClient.Send(mailMessage);
return true;
}
catch
{
mailMessage = null;
smtpClient = null;
return false;
}
}
else
{
return false;
}
}
It looks like a simple quoting problem. Look
<a href='http://localhost:49234/Index.aspx?ActivationCode='"+objUserDetailsBE.ActivationCode+"'
In here you have a single quote before http, another one after ActivationCode= and third one at the end. Looks like one is redundant, and that breaks your markup.
Correct version:
body+=#"<br /><a href='http://localhost:49234/Index.aspx?ActivationCode="+objUserDetailsBE.ActivationCode+"'>Create a login to account</a>";
The only change I did was to remove the single quote after ActivationCode=.
Also make sure the active code does not contain symbols like quotes or <>, that can also break the markup.
I'm adding confirmation email feature to my ASP.NET WebAPI project. The server can send email fine, however, the confirmation link always return "Invalid token".
I checked some reasons as pointed out here
http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/
but it seems that none of them is the root cause
Below is my code:
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
try
{
await userManager.AddToRoleAsync(user.Id, "Player");
//Generate email confirmation token
//var provider = new DpapiDataProtectionProvider("GSEP");
var provider = new MachineKeyProtectionProvider();
userManager.UserTokenProvider = new DataProtectorTokenProvider<GSEPUser>(provider.Create("EmailConfirmation"));
var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
code = System.Web.HttpUtility.UrlEncode(code);
EmailHelper emailHelper = new EmailHelper();
string callBackUrl = emailHelper.GetCallBackUrl(user, code);
EmailMessage message = new EmailMessage();
message.Body = callBackUrl;
message.Destination = user.Email;
message.Subject = "GSEP Account confirmation";
emailHelper.sendMail(message);
}
catch (Exception e)
{
return Ok(GSEPWebAPI.App_Start.Constants.ErrorException(e));
}
}
And now is EmailHelper
public class EmailHelper
{
public string GetCallBackUrl(GSEPUser user, string code)
{
var newRouteValues = new RouteValueDictionary(new { userId = user.Id, code = code });
newRouteValues.Add("httproute", true);
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext, RouteTable.Routes);
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
return callbackUrl;
}
public void sendMail(EmailMessage message)
{
#region formatter
string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
string html = "Please confirm your account by clicking this link: link<br/>";
html += HttpUtility.HtmlEncode(#"Or click on the copy the following link on the browser:" + message.Body);
#endregion
MailMessage msg = new MailMessage();
msg.From = new MailAddress("myemail#example.com");
msg.To.Add(new MailAddress(message.Destination));
msg.Subject = message.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("smtp-mail.outlook.com", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("myemail#example.com", "mypassword!");
smtpClient.Credentials = credentials;
smtpClient.EnableSsl = true;
smtpClient.Send(msg);
}
}
And 2 MachineKey class
public class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
public class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
I also added machineKey tag in Web.config as some instruction pointed out.
And finally is my confirmation email API
[AllowAnonymous]
[HttpGet]
public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return Ok("Confirm error");
}
IdentityResult result;
try
{
result = await UserManager.ConfirmEmailAsync(userId, code);
}
catch (InvalidOperationException ioe)
{
// ConfirmEmailAsync throws when the userId is not found.
return Ok("UserID not found");
}
if (result.Succeeded)
{
return Ok("Confirmation succesfully");
}
else
{
return Ok(result.Errors);
}
}
Please show me where am I go wrong
I know this is an old thread. But I though of adding the answer as it could help others.
You are using the below code
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
and the UrlHelper.Action already does the url encoding for you in the latest MVC versions. So here in your code you are doing the encoding twice (one inside the Register and another inside GetCallBackUrl using urlHelper.Action) and that is why you are getting the invalid token error.
I wonder if someone can please help with a MVC Contact Form which send an Email on submission? I think I have most elements setup, but for some reason the form appear to be sending (takes ages) then just returns back to the form and no email is received.
MailModels.cs:
namespace WebApplication1.Models
{
public class MailModels
{
public string Name { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Message { get; set; }
}
}
Contact.cshtml:
#using (Html.BeginForm("Contact", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #id = "contact-form", role = "form" }))
{
#Html.ValidationSummary()
<fieldset>
<div class="form-div-1">
<label class="name">
#Html.TextBoxFor(m => m.Name, new { #placeholder = "Name *", #type = "text" })
</label>
</div>
<div class="form-div-2">
<label class="email">
#Html.TextBoxFor(m => m.Email, new { #placeholder = "Email Address *", #type = "email" })
</label>
</div>
<div class="form-div-3">
<label class="phone notRequired">
#Html.TextBoxFor(m => m.Telephone, new { #placeholder = "Telephone Number", #type = "text" })
</label>
</div>
<div>
<label class="message">
#Html.TextAreaFor(m => m.Message, new { #placeholder = "Message *" })
</label>
</div>
<div class="button-wrapper">
<input type="submit" value="Send" name="submit" class="button"> <input type="reset" value="Reset" name="MFReset" class="button"><span>* Required Fields</span>
</div>
</fieldset>
}
HomeController.cs:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net.Mail;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using WebApplication1.Models;
using System.Text;
namespace WebApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Contact()
{
ViewBag.Message = "Test Form";
return View();
}
[HttpPost]
public ActionResult Contact(MailModels e)
{
if (ModelState.IsValid)
{
StringBuilder message = new StringBuilder();
MailAddress from = new MailAddress(e.Email.ToString());
message.Append("Name: " + e.Name + "\n");
message.Append("Email: " + e.Email + "\n");
message.Append("Telephone: " + e.Telephone + "\n\n");
message.Append(e.Message);
MailMessage mail = new MailMessage();
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.mail.yahoo.com";
smtp.Port = 465;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("yahooaccount", "yahoopassword");
smtp.Credentials = credentials;
smtp.EnableSsl = true;
mail.From = from;
mail.To.Add("yahooemailaddress");
mail.Subject = "Test enquiry from "+e.Name;
mail.Body = message.ToString();
smtp.Send(mail);
}
return View();
}
Banging my head against a brickwall with this one, any help would be much appreciated :-)
Sending an email will take time. It should be a thread. Put your code in a function. And make the following changes:
public void SendEmail(string toAddress, string fromAddress,
string subject, string message)
{
try
{
using (var mail = new MailMessage())
{
const string email = "username#yahoo.com";
const string password = "password!";
var loginInfo = new NetworkCredential(email, password);
mail.From = new MailAddress(fromAddress);
mail.To.Add(new MailAddress(toAddress));
mail.Subject = subject;
mail.Body = message;
mail.IsBodyHtml = true;
try
{
using (var smtpClient = new SmtpClient(
"smtp.mail.yahoo.com", 465))
{
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = loginInfo;
smtpClient.Send(mail);
}
}
finally
{
//dispose the client
mail.Dispose();
}
}
}
catch (SmtpFailedRecipientsException ex)
{
foreach (SmtpFailedRecipientException t in ex.InnerExceptions)
{
var status = t.StatusCode;
if (status == SmtpStatusCode.MailboxBusy ||
status == SmtpStatusCode.MailboxUnavailable)
{
Response.Write("Delivery failed - retrying in 5 seconds.");
System.Threading.Thread.Sleep(5000);
//resend
//smtpClient.Send(message);
}
else
{
Response.Write("Failed to deliver message to {0}",
t.FailedRecipient);
}
}
}
catch (SmtpException Se)
{
// handle exception here
Response.Write(Se.ToString());
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
Call that function in your controller:
[HttpPost]
public ActionResult Contact(MailModels e)
{
if (ModelState.IsValid)
{
//prepare email
var toAddress = "someadress#yahoo.co.uk";
var fromAddress = e.Email.ToString();
var subject = "Test enquiry from "+ e.Name;
var message = new StringBuilder();
message.Append("Name: " + e.Name + "\n");
message.Append("Email: " + e.Email + "\n");
message.Append("Telephone: " + e.Telephone + "\n\n");
message.Append(e.Message);
//start email Thread
var tEmail = new Thread(() =>
SendEmail(toAddress, fromAddress, subject, message));
tEmail.Start();
}
return View();
}
If you dont get email, check your spam folder
You need to implement Producer Consumer pattern for this use case. You will have to have one thread running dedicated to emails. This thread will read from the queue & send emails. In the contact method, you will just add to the queue. Its not a good idea to do time consuming operations in controller methods.
C# producer/consumer
settings to web.config
<system.net>
<mailSettings>
<smtp from="you#outlook.com">
<network host="smtp-mail.outlook.com"
port="587"
userName="you#outlook.com"
password="password"
enableSsl="true" />
</smtp>
</mailSettings>
</system.net>
Port 465 or 587?
Lots of code samples for Gmail feature port 465 but most people cannot get this to work. When they revert to port 587, their email suddenly works. According to Gmail's documentation SSL is required if you specify port 465. Many people think that setting EnableSsl to true achieves this, but in fact, it means that your app must be running under https. When you set EnableSsl to true, you actually switch TLS on, which is required for port 587. Https is not supported by the SmtpClient object. For more details, read the Remarks section of the docs on MSDN.
public void SendEmail(string toAddress, string fromAddress,string subject, string message)
{
try
{
using (var mail = new MailMessage())
{
const string email = "username#yahoo.com";
const string password = "password!";
var loginInfo = new NetworkCredential(email, password);
mail.From = new MailAddress(fromAddress);
mail.To.Add(new MailAddress(toAddress));
mail.Subject = subject;
mail.Body = message;
mail.IsBodyHtml = true;
try
{
using (var smtpClient = new SmtpClient(
"smtp.mail.yahoo.com", 465))
{
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = loginInfo;
smtpClient.Send(mail);
}
}
finally
{
//dispose the client
mail.Dispose();
}
}
}
catch (SmtpFailedRecipientsException ex chor gai )
{
foreach (SmtpFailedRecipientException t in ex.InnerExceptions)
{
var status = t.StatusCode;
if (status == SmtpStatusCode.MailboxBusye ||
status == SmtpStatusCode.MailboxUnavailableee)
{
Response.Write("Delivery failed - retrying in 5 seconds.");
System.Threading.Thread.Sleep(5000);
//resend
//smtpClient.Send(message);
}
else
{
Response.Write("Failed to deliver message to {0}",
t.FailedRecipient);
}
}
}
catch (SmtpException Se)
{
// handle exception here
Response.Write(Se.ToString());
}
catch (Exception ex)
{
Response.Write(ex.Toread());
}
}