Here are my two actions for sending emails via MVC:
[HttpGet]
// GET: EmailForms
public ActionResult EmailForm(int id)
{
EmailFormModel emailModel = new EmailFormModel();
ChosenWT cwt = new ChosenWT();
OInfo person= new OInfo();
using (var db = new OWTEntities())
{
cwt = db.ChosenWTs.Find(id);
person= db.OInfoes.Find(cwt.OID);
}
emailModel.Message = "This is paragraph 1.\n\nThis is paragraph 2.\n\nThis is paragraph 3." // issue deals with this property
emailModel.FromEmail = User.Identity.Name.Split('\\')[1] + "#domain.com";
string Logon = Common.GetLogon(person.IBM);
emailModel.ToEmail = Logon + "#domain.com";
return View(emailModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EmailForm(EmailFormModel model)
{
if (ModelState.IsValid)
{
var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
var message = new MailMessage();
message.To.Add(new MailAddress(model.ToEmail));
message.From = new MailAddress(model.FromEmail);
message.Subject = "Test Program";
message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message); // This doesn't keep the paragraph formatting like in the [HttpGet] Action.. Instead it just combines it all into 1 big paragraph..
message.IsBodyHtml = true;
using (var smtp = new SmtpClient())
{
smtp.Host = "smtp.test.server";
await smtp.SendMailAsync(message);
return RedirectToAction("Index", "OInfoes");
}
}
return View(model);
}
If you read the comments I put in the code above, that is the issue with this code.
I can format the Message so that when the user first comes to the page, the string is formatted into paragraph form.. but when I click Send, the HttpPost Action takes the message and ignores the \n\n and combines it all into one giant paragraph.
So I have tried to include <p></p> symbols into the string, but when I hit submit, I get an error stating that those characters are potentially dangerous.
Is there a way for the formatting to stay the same when i submit?
Any help is appreciated.
The reason why you are getting the error is, when a form is submitted, the asp.met mvc framework will inspect the request body to see whether it has any potentially dangerous content as HTML markup(Think about script injection). If it detects any dangerous content,the Request Validation module will throw an error. This is by design
You can apply AllowHtml attribute to the property which holds the html markup in your view model class so that the request validation framework won't reject the data submitted.
public class EmailFormModel
{
[AllowHtml]
public string Message { set;get;}
public string FromEmail {set;get;}
//Other properties of view model goes here
}
Related
I have designed an Email Template from Razor Syntax. When I send this template as Email using C# code and SMTP protocol, I get bare Razor and HTML markups as Email Body. Am I wrong in this approach? Are Razor Pages allowed as Email Template?
Here is my Page
#inherits ViewPage
#{
Layout = "_Layout";
ViewBag.Title = "";
}
<div class="container w-420 p-15 bg-white mt-40">
<div style="border-top:3px solid #22BCE5"> </div>
<span style="font-family:Arial;font-size:10pt">
Hello <b>{UserName}</b>,<br /><br />
Thanks for Registering to XYZ Portal<br /><br />
<a style="color:#22BCE5" href="{Url}">Click to Confirm Email</a><br />
<br /><br />
Thanks<br />
Admin (XYZ)
</span>
Update..
using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/ContentPages/EmailConfTemplate.cshtml")))
{
body = reader.ReadToEnd();
//Replace UserName and Other variables available in body Stream
body = body.Replace("{UserName}", FirstName);
}
Later On I am replacing the SMTP Code as ..
MailMessage message = new MailMessage(
ApplicationWideData.fromEmailId, // From field
ToEmailId, // Recipient field
"Click On HyperLink To Verify Email Id", // Subject of the email message
body
);
You do not need any special libraries to render a Razor view to a string in an ASP.NET MVC application.
Here is how you do it in MVC Core 3
public static class ViewToStringRenderer
{
public static async Task<string> RenderViewToStringAsync<TModel>(IServiceProvider requestServices, string viewName, TModel model)
{
var viewEngine = requestServices.GetRequiredService(typeof(IRazorViewEngine)) as IRazorViewEngine;
ViewEngineResult viewEngineResult = viewEngine.GetView(null, viewName, false);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + string.Join("\r\n", viewEngineResult.SearchedLocations));
}
else
{
IView view = viewEngineResult.View;
var httpContextAccessor = (IHttpContextAccessor)requestServices.GetRequiredService(typeof(IHttpContextAccessor));
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new RouteData(), new ActionDescriptor());
var tempDataProvider = requestServices.GetRequiredService(typeof(ITempDataProvider)) as ITempDataProvider;
using var outputStringWriter = new StringWriter();
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model },
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
outputStringWriter,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return outputStringWriter.ToString();
}
}
}
In the controller
string str = await ViewToStringRenderer.RenderViewToStringAsync(HttpContext.RequestServices, $"~/Views/Emails/MyEmailTemplate.cshtml", new MyEmailModel { Prop1 = "Hello", Prop2 = 23 });
In ConfigureServices() in Startup.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Here is how you do it in MVC 5
public static class ViewToStringRenderer
{
public static string RenderViewToString<TModel>(ControllerContext controllerContext, string viewName, TModel model)
{
ViewEngineResult viewEngineResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + viewEngineResult.SearchedLocations);
}
else
{
IView view = viewEngineResult.View;
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary<TModel>(model), new TempDataDictionary(), stringWriter);
view.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
}
}
Then, from the controller
ViewToStringRenderer.RenderViewToString(this.ControllerContext, "~/Views/Emails/MyEmailTemplate.cshtml", model);
After you have the email content, it is easy to send the email using MailMessage and SmtpClient.
Email messages only understand two formats: plain text and HTML. Since Razor is neither, it will need to be processed by some engine, so that it gives you back the generated HTML.
That's exactly what happens when you use Razor in ASP.NET MVC, behind the scenes. The Razor file is compiled into a internal C# class, that gets executed, and the result of the execution is the string content of the HTML, that gets sent to the client.
Your problem is that you want and need that processing to run, only to get the HTML back as a string, instead of being sent to the browser. After that you can do whatever you want with the HTML string, including sending it as an e-mail.
There are several packages that include this power, and I've used Westwind.RazorHosting successfully, but you can also use RazorEngine with similar results. I would prefer RazorHosting for standalone non-web applications, and RazorEngine for web applications
Here is a (sanitized) version of some of my code - I'm using Westwind.RazorHosting to send razor-formatted emails from a windows service, using a strongly typed view.
RazorFolderHostContainer host = = new RazorFolderHostContainer();
host.ReferencedAssemblies.Add("NotificationsManagement.dll");
host.TemplatePath = templatePath;
host.Start();
string output = host.RenderTemplate(template.Filename, model);
MailMessage mm = new MailMessage { Subject = subject, IsBodyHtml = true };
mm.Body = output;
mm.To.Add(email);
var smtpClient = new SmtpClient();
await smtpClient.SendMailAsync(mm);
Have you took a look at MVC Mailer?
It's a free package available from GitHub (https://github.com/smsohan/MvcMailer)
There is a step by step guide for it too https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
It's also on Nuget too. https://www.nuget.org/packages/MvcMailer
Essentially it will parse your razor view into html.
Check out a razor processor like RazorEngine (https://razorengine.codeplex.com/) which is available on NuGet. It processes razor to create an output, which is what you'd then use as the body of your email.
The Mailzory project is a valuable and convenient choice for sending emails which have Razor templates.
// template path
var viewPath = Path.Combine("Views/Emails", "hello.cshtml");
// read the content of template and pass it to the Email constructor
var template = File.ReadAllText(viewPath);
var email = new Email(template);
// set ViewBag properties
email.ViewBag.Name = "Johnny";
email.ViewBag.Content = "Mailzory Is Funny";
// send email
var task = email.SendAsync("mailzory#outlook.com", "subject");
task.Wait()
this project is hosted at Github. Also there is a nuget package available for Mailzory.
I have an ASP.NET Core application which use Identity for user management.
I have a MailProvider which prepares an email to send via smtp for account activation purposes:
// ...
var activationMailViewModel = new ActivationMailViewModel()
{
LastName = user.LastName,
FirstName= user.FirstName,
UserName = userName,
Email = user.Email,
CompanyName = companyName,
Url = url.Action("ConfirmEmail", "Account", new { Area = "", code = token, userId = user.Id }, request.Scheme)
};
// ...
var result = Engine.Razor.RunCompile(new LoadedTemplateSource($"Activation", path), "SendUserAccountCreation" + Guid.NewGuid(), null, activationMailViewModel);
// ...
var mailMessage = new MailMessage(
new MailAddress("kyc#vente-privee.com", "KYC-vente-privee.com"),
new MailAddress(user.Email, userName))
{
Subject = GetGlobalString("ActivationMail_Subject", cultureCode),
BodyEncoding = System.Text.Encoding.UTF8,
SubjectEncoding = System.Text.Encoding.UTF8
};
<p>ACTIVATE MY ACCOUNT</p>
However it seems that the link generated can be interpreted in two different ways due to the transcription of the character & into & in the query string of the url.
http://base.url.net/Account/ConfirmEmail?code=CfDJ8PtYvJr8Ve1GnxXJykedIzKTQDg%2FTXBwV6NmIYMy8Gi7yUbqZagGbZRacKSFrE717h%2FGjmm6l8QA3knPPgxyNnM1vxe3wb6KnFsGtZUOMTas7QhX1MW5dE4cU5sorA99Dz03zV8ldVMOMP5BGfUrts2nNQqbs8dNLPNgupdkNzaWa4q6fM5u9E99CzRcFjAn7nnd57Ht3IIREAqz6lqufFYo469%2BN2VJxmNJJ1p6OAvO6dMJ9M%2Fzdz3xkpBajJbxRw%3D%3D**&**userId=21e4673c-f121-417f-9837-7f5b234f6f01
http://base.url.net/Account/ConfirmEmail?code=CfDJ8PtYvJr8Ve1GnxXJykedIzKTQDg%2FTXBwV6NmIYMy8Gi7yUbqZagGbZRacKSFrE717h%2FGjmm6l8QA3knPPgxyNnM1vxe3wb6KnFsGtZUOMTas7QhX1MW5dE4cU5sorA99Dz03zV8ldVMOMP5BGfUrts2nNQqbs8dNLPNgupdkNzaWa4q6fM5u9E99CzRcFjAn7nnd57Ht3IIREAqz6lqufFYo469%2BN2VJxmNJJ1p6OAvO6dMJ9M%2Fzdz3xkpBajJbxRw%3D%3D**&**userId=21e4673c-f121-417f-9837-7f5b234f6f01
Which can be problematic for the my AccountController:
[Authorize]
public class AccountController : BaseController
{
// GET: /Account/ConfirmEmail
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string code, string userId)
{
if (code == null || userId == null)
{
return View("Error");
}
// Rest of the code... not relevant to the question
}
If the browser / mail client interprets & as & then the userId will be set to null and the account / email cannot be confirmed.
For example:
On ProtonMail: the link on which I can click leads to an address which use & in the query string, which is just fine.
On Gmail: & and hence the link does not confirm the email.
However in both email providers, the plain text shows that the url has been generated with the Razor engine is: &.
What is the best strategy so that my users do not end up with a link that does not work.
Seems the issue was about the raw formatting which was not applied to the email.
The answer given here on SO:
When doing e-mails, I use the RazorEngineService in RazorEngine.Templating, e.g. in my case, it looks like this:
using RazorEngine.Templating;
RazorEngineService.Create().RunCompile(html, ...)
Assuming you are using the same assembly, #Html.Raw does NOT exist with this usage. I > was finally able to get raw HTML output by doing this in my e-mails:
#using RazorEngine.Text
#(new RawString(Model.Variable))
I have designed an Email Template from Razor Syntax. When I send this template as Email using C# code and SMTP protocol, I get bare Razor and HTML markups as Email Body. Am I wrong in this approach? Are Razor Pages allowed as Email Template?
Here is my Page
#inherits ViewPage
#{
Layout = "_Layout";
ViewBag.Title = "";
}
<div class="container w-420 p-15 bg-white mt-40">
<div style="border-top:3px solid #22BCE5"> </div>
<span style="font-family:Arial;font-size:10pt">
Hello <b>{UserName}</b>,<br /><br />
Thanks for Registering to XYZ Portal<br /><br />
<a style="color:#22BCE5" href="{Url}">Click to Confirm Email</a><br />
<br /><br />
Thanks<br />
Admin (XYZ)
</span>
Update..
using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/ContentPages/EmailConfTemplate.cshtml")))
{
body = reader.ReadToEnd();
//Replace UserName and Other variables available in body Stream
body = body.Replace("{UserName}", FirstName);
}
Later On I am replacing the SMTP Code as ..
MailMessage message = new MailMessage(
ApplicationWideData.fromEmailId, // From field
ToEmailId, // Recipient field
"Click On HyperLink To Verify Email Id", // Subject of the email message
body
);
You do not need any special libraries to render a Razor view to a string in an ASP.NET MVC application.
Here is how you do it in MVC Core 3
public static class ViewToStringRenderer
{
public static async Task<string> RenderViewToStringAsync<TModel>(IServiceProvider requestServices, string viewName, TModel model)
{
var viewEngine = requestServices.GetRequiredService(typeof(IRazorViewEngine)) as IRazorViewEngine;
ViewEngineResult viewEngineResult = viewEngine.GetView(null, viewName, false);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + string.Join("\r\n", viewEngineResult.SearchedLocations));
}
else
{
IView view = viewEngineResult.View;
var httpContextAccessor = (IHttpContextAccessor)requestServices.GetRequiredService(typeof(IHttpContextAccessor));
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new RouteData(), new ActionDescriptor());
var tempDataProvider = requestServices.GetRequiredService(typeof(ITempDataProvider)) as ITempDataProvider;
using var outputStringWriter = new StringWriter();
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model },
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
outputStringWriter,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return outputStringWriter.ToString();
}
}
}
In the controller
string str = await ViewToStringRenderer.RenderViewToStringAsync(HttpContext.RequestServices, $"~/Views/Emails/MyEmailTemplate.cshtml", new MyEmailModel { Prop1 = "Hello", Prop2 = 23 });
In ConfigureServices() in Startup.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Here is how you do it in MVC 5
public static class ViewToStringRenderer
{
public static string RenderViewToString<TModel>(ControllerContext controllerContext, string viewName, TModel model)
{
ViewEngineResult viewEngineResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + viewEngineResult.SearchedLocations);
}
else
{
IView view = viewEngineResult.View;
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary<TModel>(model), new TempDataDictionary(), stringWriter);
view.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
}
}
Then, from the controller
ViewToStringRenderer.RenderViewToString(this.ControllerContext, "~/Views/Emails/MyEmailTemplate.cshtml", model);
After you have the email content, it is easy to send the email using MailMessage and SmtpClient.
Email messages only understand two formats: plain text and HTML. Since Razor is neither, it will need to be processed by some engine, so that it gives you back the generated HTML.
That's exactly what happens when you use Razor in ASP.NET MVC, behind the scenes. The Razor file is compiled into a internal C# class, that gets executed, and the result of the execution is the string content of the HTML, that gets sent to the client.
Your problem is that you want and need that processing to run, only to get the HTML back as a string, instead of being sent to the browser. After that you can do whatever you want with the HTML string, including sending it as an e-mail.
There are several packages that include this power, and I've used Westwind.RazorHosting successfully, but you can also use RazorEngine with similar results. I would prefer RazorHosting for standalone non-web applications, and RazorEngine for web applications
Here is a (sanitized) version of some of my code - I'm using Westwind.RazorHosting to send razor-formatted emails from a windows service, using a strongly typed view.
RazorFolderHostContainer host = = new RazorFolderHostContainer();
host.ReferencedAssemblies.Add("NotificationsManagement.dll");
host.TemplatePath = templatePath;
host.Start();
string output = host.RenderTemplate(template.Filename, model);
MailMessage mm = new MailMessage { Subject = subject, IsBodyHtml = true };
mm.Body = output;
mm.To.Add(email);
var smtpClient = new SmtpClient();
await smtpClient.SendMailAsync(mm);
Have you took a look at MVC Mailer?
It's a free package available from GitHub (https://github.com/smsohan/MvcMailer)
There is a step by step guide for it too https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
It's also on Nuget too. https://www.nuget.org/packages/MvcMailer
Essentially it will parse your razor view into html.
Check out a razor processor like RazorEngine (https://razorengine.codeplex.com/) which is available on NuGet. It processes razor to create an output, which is what you'd then use as the body of your email.
The Mailzory project is a valuable and convenient choice for sending emails which have Razor templates.
// template path
var viewPath = Path.Combine("Views/Emails", "hello.cshtml");
// read the content of template and pass it to the Email constructor
var template = File.ReadAllText(viewPath);
var email = new Email(template);
// set ViewBag properties
email.ViewBag.Name = "Johnny";
email.ViewBag.Content = "Mailzory Is Funny";
// send email
var task = email.SendAsync("mailzory#outlook.com", "subject");
task.Wait()
this project is hosted at Github. Also there is a nuget package available for Mailzory.
I have a form but the user's data is not stored anywhere, just sent in an email. Does anyone know of an easy way to allow the user to attach a file?
As of now, when the user clicks submit, jquery collects the data and sends it to 'AjaxController.cs'. (A form element is not used)
HTML
<div class="form">
<input type="text" name="Name">
<input type="file" name="File">
<button>Submit</button>
</div>
JS
$(document).ready(function(){
$('button').click(function(){
var data = {};
$('input').each(function(){
data[this.name] = this.value;
}
$.post('/Ajax/Email', data, function(){
alert("Email Sent");
});
});
}
C#
public class AjaxController : Controller
{
public ActionResult Email()
{
MailMessage message = new MailMessage("from#fake.com","marketing#fake.com");
foreach (string form_inputs in Request.Form.Keys)
{
String input_name = form_inputs.ToString();
String input_value = Request.Form[form_inputs].Trim();
if(input_name == "File")
{
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(input_value); //ERROR
message.Attachments.Add(attachment);
}
if (input_name == "Name")
{
message.Body = "Name: " + input_value;
}
}
SmtpClient client = new SmtpClient();
client.Port = 25;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Host = "SMTP.fake.com";
client.Send(message);
}
}
/Ajax/Email simply returns 'Mail Sent!"
I'm getting an error that basically says the uploaded file does not exist locally - of course - because it hasn't been uploaded. Where does the file exist at this point, how do I access it?
Files uploaded in MVC are in the Request collection as an HttpPostedFileBase type. You can use this to get a stream instance of the file in memory on the server and attach it directly to the e-mail. When using a FORM tag, you must set the the enctype="multipart/form-data" in your form.
In your controller:
public class AjaxController : Controller
{
public ActionResult Email()
{
MailMessage message = new MailMessage("from#fake.com","marketing#fake.com");
foreach (string form_inputs in Request.Form.Keys)
{
String input_name = form_inputs.ToString();
String input_value = Request.Form[form_inputs].Trim();
if(input_name == "File")
{
HttpPostedFileBase file = Request.Files[input_name];
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(file.InputStream, file.FileName); //ERROR
message.Attachments.Add(attachment);
}
if (input_name == "Name")
{
message.Body = "Name: " + input_value;
}
}
SmtpClient client = new SmtpClient();
client.Port = 25;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Host = "SMTP.fake.com";
client.Send(message);
}
}
I also feel compelled to mention the fact that this could be VERY insecure (dangerous) depending on how you're planning to implement this. Please be sure to perform some verification on the file prior to sending it (in memory Virus scan / content type restrictions, etc...).
Because you're using Ajax (which the POST method uses under the covers), you'll have some additional challenges. Up until recently, Ajax file uploads had to be done with an iframe hack. With modern browsers that support XHR2, it can be done only using the FormData object in JavaScript. Luckily, these factors won't affect the server-side code. See this Question for more detail on this:
jQuery Ajax File Upload
For more on using FormData, see here: Sending multipart/formdata with jQuery.ajax
Here is an in-depth article discussing ajax form uploads: http://abandon.ie/notebook/simple-file-uploads-using-jquery-ajax
I am building an MVC email form and everything on the tutorial page works except if I keep [HttpPost] the page breaks.
I dont think I am forgeting an Import.
What will fix this so the Email Form will post or rather [HttpPost] will not cause the error?
I also tried [System.Web.Mvc.HttpPost]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Net.Mail;
using System.Text;
using SW.Models;
namespace SW.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
//ViewBag.Message = "Your application description page.";
return View();
}
//[System.Web.Mvc.HttpPost]
public ActionResult Contact(ContactModels c)
{
//ViewBag.Message = "Your contact page.";
if (ModelState.IsValid)
{
try
{
MailMessage msg = new MailMessage();
SmtpClient smtp = new SmtpClient();
MailAddress from = new MailAddress(c.Email.ToString());
StringBuilder sb = new StringBuilder();
msg.To.Add("mail#hotmail.com");
msg.Subject = "Contact Us";
msg.IsBodyHtml = false;
smtp.Host = "mail.mail.com";
smtp.Port = 25;
sb.Append("First name: " + c.FirstName);
sb.Append(Environment.NewLine);
sb.Append("Last name: " + c.LastName);
sb.Append(Environment.NewLine);
sb.Append("Email: " + c.Email);
sb.Append(Environment.NewLine);
sb.Append("Comments: " + c.Comment);
smtp.Send(msg);
msg.Dispose();
return View("Success");
}
catch (Exception)
{
return View("Error");
}
}
return View();
}
}
}
As Soon as I goto Contact I get the error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Home/Contact
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18446
It's hard to say for sure without knowing what error message you are getting, but I think this is the problem: You'll want to have separate GET and POST methods for the Contact() action. The GET handles the case where you are viewing the contact page. The POST handles the case where you are submitting your form.
It might look something like this:
[System.Web.Mvc.HttpGet]
public ActionResult Contact()
{
return View(new ContactModels());
}
[System.Web.Mvc.HttpPost]
public ActionResult Contact(ContactModels c)
{
//ViewBag.Message = "Your contact page.";
if (ModelState.IsValid)
{
try
{
MailMessage msg = new MailMessage();
SmtpClient smtp = new SmtpClient();
MailAddress from = new MailAddress(c.Email.ToString());
StringBuilder sb = new StringBuilder();
msg.To.Add("mail#hotmail.com");
msg.Subject = "Contact Us";
msg.IsBodyHtml = false;
smtp.Host = "mail.mail.com";
smtp.Port = 25;
sb.Append("First name: " + c.FirstName);
sb.Append(Environment.NewLine);
sb.Append("Last name: " + c.LastName);
sb.Append(Environment.NewLine);
sb.Append("Email: " + c.Email);
sb.Append(Environment.NewLine);
sb.Append("Comments: " + c.Comment);
smtp.Send(msg);
msg.Dispose();
return View("Success");
}
catch (Exception)
{
return View("Error");
}
}
return View();
}
If you have only a single method with an HttpPost attribute, it's only available for HTTP POST requests, so attempting to HTTP GET the page in your web browser will fail.
Actions without attributes are by default GET methods. If you add the explicit HttpPost attribute to your method, it will no longer work for GET requests, such as displaying the contacts page in the first place.
You can use the [AcceptVerbs(HttpVerbs.Get|HttpVerbs.Post)] attribute syntax to allow both.
You have to have both Get and Post actions or remove the HttpPost attribute and assign your form method to "GET".