How to upload a file to be an attachment in an email? - c#

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

Related

ASP.NET Core Web API POST request works with Postman but not in C#/React

I have a Contact Us page created in React that has three fields(Name,Email,Message), when I click the Submit button, it does not send an email to the specified user. When I used Postman to test my Web API created in C#, it sends the email correctly. I don't know what's happening since it does not throw any error.
I'm using using using System.Net.Mail; to perform smtp emails.
Here is my web api code:
[HttpPost]
public void Post(Contact contact)
{
using (SmtpClient client = new SmtpClient("smtp.gmail.com", 587))
{
MailAddress to = new MailAddress(contact.Email);
MailAddress from = new MailAddress(_email);
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(_email, _password);
client.EnableSsl = true;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
using (MailMessage message = new MailMessage(from, to))
{
message.Subject = $"Hello {contact.Name}...";
message.Body = contact.Message;
try
{
client.Send(message);
}
catch (SmtpException smtp)
{
Console.WriteLine(smtp);
}
}
}
Here is my React code:
useEffect(() => {
if (trigger) {
axios({
method: "post",
url: `${proxy} + ${url}`,
headers: { "Content-Type": "application/json" },
data: data,
}).then((response) => {
console.log(response.config.data);
});
}
}, [trigger]);
// My code performs post request when the submit button is changed.
// When the submit button is clicked,it sets the trigger's state to true to perform the post request.
Screenshot:
Edit: Added Request Headers + Response Tab:
Edit: Added Project Structure

MailMessage sends mail with empty subject and attachments

So I'm trying to send an email through my relay smtp with an html body, subject and optional attachments. The sending works without exceptions however, the mail which is being sent ends up with an empty subject and no attachments which should get files from the wwwroot folder of my web application which is being hosted on the same domain as my API and console app. This console app will be called from the task scheduler. This program has my API as dependency so that it can call the ProcessQueue task. this one is being called correctly from my console application. To get data for the email the code will retreive data from the MailQueue table and then fill the mailmessage like so:
public async Task ProcessQueue(int range, bool send)
{
SmtpClient client = new SmtpClient
{
Host = "outbound.domain",
Port = 587,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("email#domain.com", "")
};
var items = await _context.MailQueues.Take(range).ToListAsync();
MailMessage message = new MailMessage();
foreach (var item in items)
{
try
{
message.From = new MailAddress(item.From);
message.Subject = item.Subject; // The subject is being filled correctly in my situation, but when the email arrives it isn't
message.IsBodyHtml = true;
message.To.Add(item.To);
message.Body = item.Content;
if (send)
{
AddAttachments(message, item.Docs);
client.Send(message);
_context.MailQueues.Remove(item);
message.To.Clear();
}
}
catch(Exception ex)
{
item.Exception = ex.ToString();
_context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
}
The attachment method:
private void AddAttachments(MailMessage message, string docs)
{
if (docs != null)
{
List<string> list = JsonConvert.DeserializeObject<List<string>>(docs);
foreach (string item2 in list)
{
Attachment item = new Attachment(HttpContext.Current.Server.MapPath("/wwwroot/documents/") + item2)
{
Name = item2
};
message.Attachments.Add(item);
}
}
}
The structure of my domain:
domain.com > webapplicatie (contains my web app and its wwwroot folder)
domain.com > webapi (contains my web api)
domain.com > mailqueuer (the location of my console application)
My goal is to send the message with optional attachments, which are located in the web app's wwwroot folder, and its subject. All the data of the MailQueue objects are filled! but still I get this problem.
Does somebody know a solution to this?
I solved this problem by putting the database and smtp logic for the MailQueue into the console application. I don't exactly know why my question isn't working but I'm open for answers and suggestions!

ASP.Net C# - Open default Email client with new Email having body filled with informations

As the title says, using C# code-behind of a ASP.Net project, I would like to open the user's default mail client with a message's body already filled with certain information.
I was able to directly send a message with information in it:
private static bool EnvoieCourriel(string adrCourriel, string corps, string objet, string envoyeur, Attachment atache)
{
SmtpClient smtp = new SmtpClient();
MailMessage msg = new MailMessage
{
From = new MailAddress(envoyeur),
Subject = objet,
Body = corps,
IsBodyHtml = true
};
if (atache != null)
msg.Attachments.Add(atache);
try
{
msg.To.Add(adrCourriel);
smtp.Send(msg);
}
catch
{
return false;
}
return true;
}
I was also able to open the user's default email client :
string email = op.CourrielOperateur1;
ClientScript.RegisterStartupScript(this.GetType(), "mailto", "parent.location='mailto:" + email + "'", true);
But now... I would like to open the client just like the second example but the body must be already filled with a default text...
Any ideas would be appreciated.
C# can't do this directly. In your case you need to use c# combined with JS to get this working.
See this Answer
As described by RFC 6068, mailto allows you to specify subject and
body, as well as cc fields. For example:
mailto:username#example.com?subject=Subject&body=message%20goes%20here
User doesn't need to click a link if you force it to be opened with
JavaScript
window.location.href =
"mailto:user#example.com?subject=Subject&body=message%20goes%20here";
Be aware that there is no single, standard way in which browsers/email
clients handle mailto links (e.g. subject and body fields may be
discarded without a warning). Also there is a risk that popup and ad
blockers, anti-virus software etc. may silently block forced opening
of mailto links.
Here is a working example:
ASP Page:
<tr>
<td>
<asp:Label ID="lblEmail" runat="server" Text="Email: "></asp:Label>
</td>
<td>
<asp:hyperlink id="lnkEmail1" runat="server" navigateurl="mailto:user#example.com?subject=MessageTitle&body;=MessageContent" target="" text="" xmlns:asp="#unknown"/>
</td>
</tr>
C#:
//call this in !ispostback in page_load
protected void BuildEmailAsLink()
{
//Email is different because we have to make the link clickable.
//navigateurl="mailto:user#example.com?subject=MessageTitle&body=MessageContent"
var email = lnkEmail1.Text;
//Only need to load the email address once on pageload. otherwise reuse it from the UI.
if (!string.IsNullOrEmpty(email) && (email.Length > 1) && email.Contains("#"))
{
//continue;
}
else
{
email = lnkEmail1.Text.Trim();
}
if (string.IsNullOrEmpty(email) == false)
{
lnkEmail1.NavigateUrl = lnkEmail1.NavigateUrl.Replace("user#example.com", email);
lnkEmail1.NavigateUrl = lnkEmail1.NavigateUrl.Replace("MessageTitle", "Reaching Out");
lnkEmail1.NavigateUrl = lnkEmail1.NavigateUrl.Replace("MessageContent",
string.IsNullOrEmpty(lblFirstName.Text.Trim()) == false
? string.Format("Hi {0},", lblFirstName.Text.Trim())
: "Hi,");
lnkEmail1.Text = email;
lnkEmail1.Visible = true;
}
}

How to send an HTML form in asp.net c# by email?

In my ASP.Net C# website, I got an order form which I want to be send via email by submitting it. The form elements are HTML and the calculations are done by JavaScript in client-side, and it has lots of form elements.
I want to be able to send the form and its filled contents by user, as PDF or JPG via email.
Maybe the form should be captured as a snapshot from client-side as an image or a print file, then maybe the file can be send from server-side by email.
I'd highly appreciate if you give me a practical described solution. Here is some parts of code as sample:
<div id="cblDomain">
<input id="cblDomain_1" value="10" onchange="subsumDomain()" type="checkbox" name="cblDomain" checked="checked"><label for="cblDomain_1">com - 10</label><br>
<input id="cblDomain_2" value="10" onchange="subsumDomain()" type="checkbox" name="cblDomain"><label for="cblDomain_2">net - 10</label><br>
<input id="cblDomain_3" value="5" onchange="subsumDomain()" type="checkbox" name="cblDomain"><label for="cblDomain_3">info - 5</label><br>
<input id="cblDomain_4" value="10" onchange="subsumDomain()" type="checkbox" name="cblDomain"><label for="cblDomain_4">me - 10</label>
</div>
<select name="ddlDomainPeriod" onchange="subsumDomain()" id="ddlDomainPeriod">
<option value="1">1 yr</option>
<option value="2">2 yrs</option>
<option value="3">3 yrs</option>
<option value="4">4 yrs</option>
<option value="5">5 yrs</option>
</select>
<div name="sum" id="sumDomain">10</div>
<script type="text/javascript">
function subsumDomain() {
var _sum = 0;
var _cblDomain = document.getElementsByName('cblDomain');
for (i = 0; i < _cblDomain.length; i++) {
if (_cblDomain[i].checked == true)
_sum += Number(_cblDomain[i].value);
}
var _domainPeriod = Number(document.getElementById('ddlDomainPeriod').options[document.getElementById('ddlDomainPeriod').selectedIndex].value);
document.getElementById('sumDomain').innerHTML = moneyConvert(_sum * _domainPeriod);
subTotal();
}
function subsumHost() {
var _hostPrice = Number(document.getElementById('ddlHost').options[document.getElementById('ddlHost').selectedIndex].value);
var _hostPeriod = Number(document.getElementById('ddlHostPeriod').options[document.getElementById('ddlHostPeriod').selectedIndex].value);
_hostDiscount = 0;
if (_hostPeriod > 1)
_hostDiscount = (_hostPrice * _hostPeriod) * 0.2;
document.getElementById('sumHost').innerHTML = moneyConvert((_hostPrice * _hostPeriod) - _hostDiscount);
subTotal();
}
</script>
Any kind help would be highly appreciated (^_^)
Kardo
Sounds like a long process. Submit, convert to pdf, save to HDD, attache to email, send email. You can do it but I would consider sending a HTML email. You just store the data (order) in your DB and send the email on a preformed email template. Let the end user print it to pdf or paper etc...
If you really want to do the pdf thing you will need to find a decent library as already suggested.
Well this is how you send the email. I like to create a re-useable email class. You don't have to though if that doesn't suit your needs. But hey, if your gonna create an email, Why not make it an object?
using System.Net.Mail;
public class Email
{
public MailAddress From { get; set; }
public MailAddress To { get; set; }
public string Password { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public string Host { get; set; }
public int Port { get; set;}
public List<Attachment> attachmentsList = new List<Attachment>();
public void send()
{
//send email
var smtp = new SmtpClient
{
Host = Host,
Port = Port,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential(From.Address, Password),
Timeout = 120000 //2mins
};
MailMessage message = new MailMessage(From.Address, To.Address);
message.Subject = Subject;
message.Body = Body;
message.IsBodyHtml = true;
foreach(Attachment attachment in attachmentsList){
if (attachment != null)
{
message.Attachments.Add(attachment);
}
}
try
{
smtp.Send(message);
}
catch(Exception e){
throw e;
}
}
}
Then you need to create your pdf or whatever you choose. Save it to your HDD somewhere. create your email and attach the file(s) as an email attachment (or just send the html body. Use stringReplace() to replace values in an email template. (#price #address #companyname etc).
Email newMail = new Email();
newMail.From = new MailAddress("someone#somewhere.com", "Your Name");
newMail.Password = "your outgoing mail password");
newMail.To = new MailAddress("someone#somewhere.com", "Recipient Name");
newMail.Subject = "Your Subject";
newMail.Body = "Your email body";
newMail.Host = smtp.example.com;
newMail.Port = 123;
//add the attachments (example)
foreach (string fileLocation in AttachmentsList)
{
newMail.attachmentsList.Add(new Attachment(fileLocation));
}
newMail.send();
I Hope that helps in some way...
If you are looking to grab your html form and generate a PDF, my favorite tool is wkhtmltopdf. You would have to have this installed on your server though (I'd love to know if others found a .net library for wkhtmltopdf! :]).
Once installed its commandline is very simple:
wkhtmltopdf www.myhomepage.com output.pdf
Calling it from .net is simple too, example:
Calling wkhtmltopdf to generate PDF from HTML
There are also .net libraries like iTextSharp that you can use to generate pdfs and other static output types.

Unable to send E-mail with Attachment

My issue is this that I am trying to make use of email sending task at my website for the admin individual.
When he selects the email ids from the available data, adds an attachment and sends the email, it was never received by user. However, if he is using simple mailing ie. without any attachment, user receives it.
Can you help please ?
My coding is given below :-
public partial class SahibAdmin_emailNewsletter : System.Web.UI.Page
{
// ...
private void SendNewsletter(string emailId)
{
System.Web.Mail.MailMessage message = new System.Web.Mail.MailMessage();
message.To = emailId;
message.From = "info#sahibimports.com";
message.Subject = "Please See: Newsletter from Sahib imports";
message.BodyFormat = System.Web.Mail.MailFormat.Text;
message.Body = txtBody.Text.ToString();
if (msgUpload.HasFile)
{
//string strFileName = msgUpload.FileName;
//msgUpload.PostedFile.SaveAs(Server.MapPath(strFileName));
//System.Web.Mail.MailAttachment attach =
// new System.Web.Mail.MailAttachment(Server.MapPath(strFileName));
//message.Attachments.Add(attach);
message.Attachments.Add(new Attachment(
FileUpload.PostedFile.InputStream, FileUpload.FileName));
}
System.Web.Mail.SmtpMail.Send(message);
Response.Flush();
}
According to http://msdn.microsoft.com/en-us/library/6sdktyws.aspx your Attachment constructor is trying to set the ContentType with the second parameter but you're passing in a filename, are you sure that is correct?
You should probably change that part to something like:
ContentType contentType = // create suitable type here based on your file format
Attachment attachment = new Attachment(
FileUpload.PostedFile.InputStream,
contentType
);
attachment.ContentDisposition.FileName = FileUpload.FileName;
message.Attachments.Add(attachment);
You are trying to use System.Net.Mail.Attachment with System.Web.Mail.MailMessage.
These API`s are incompatible with each other. System.Web.Mail.MailMessage only supports System.Web.Mail.MailAttachment, not System.Net.Mail.Attachment.

Categories