System.Net.Mail.MailMessage/System.Net.Mail.SmtpClient Sending Duplicate Emails - c#

The code below uses System.Net.Mail.MailMessage/System.Net.Mail.SmtpClient to email files from a ASP.NET/C# 3.5SP1 application running on IIS7 on Windows 2008R2. Even though we haven't changed the code in 3+ years, it has recently started sending duplicate emails. For example, if me#me.com is the currentVendor.Email, me#me.com receives 2 separate emails exactly the same. Any ideas? Would a Windows Update have caused this?
Vendor currentVendor = Vendor.GetCurrent();
string POLocation = Vendor.GetPOLocation();
#if !DEBUG
MailMessage mailer = new MailMessage("orders#perks.com", "resdev#perks.com");
string[] addresses = currentVendor.Email.Split(new char[] { ';', ',' });
foreach (string recip in addresses)
{
mailer.To.Add(recip.Trim());
}
#else
MailMessage mailer = new MailMessage("orderstest#me.com", "devtest#me.com");
#endif
mailer.Subject = String.Format("{0} V2 Purchase Orders - {1}", currentVendor.Name, DateTime.Today.ToShortDateString());
mailer.IsBodyHtml = true;
mailer.Body = "Please find attached..... <br/>" +
"This email is system generated. If you have any trouble please, contact us";
mailer.Attachments.Add(new Attachment(POLocation));
SmtpClient mailClient = new SmtpClient();
mailClient.Send(mailer);
Thanks in advance!

Try to check if this code:
Vendor currentVendor = Vendor.GetCurrent();
does not return duplicated email addresses?
There is only one call to MailClient.Send() method:
mailClient.Send(mailer);
But make sure you don't call the entire code snippet which you have pasted more than once!

Related

How do you create a PDF after submitting a form and attach it to an automated email in ASP.NET MVC C#?

I am having the hardest time figuring out how to create a pdf and attach it to an automated email. I thought it wouldn't be that hard but have quickly found out that it is much more complex than I imagined. Anyways, what I am doing is I have an order form, and when the customer fills out an order and submits it, I want it to generate a PDF for that order and attach it to an automated confirmation email. I am currently using Rotativa to generate the pdf and if I just ran the action result for generating it, it works perfectly fine which looks something like this:
public ActionResult ProcessOrder(int? id)
{
string orderNum = "FulfillmentOrder" + orderDetail.OrderID + ".pdf";
var pdf = new ActionAsPdf("OrderReportPDF", new { id = orderDetail.OrderID }) { FileName = orderNum };
return pdf;
}
When I added the function to send an automated email after the order form was submitted, that works perfectly fine with just the email by itself. But I can't seem to figure out how to generate the pdf and attach it to the email. The report view that gets the data from the order form is called "OrderReportPDF". My order form is called "Checkout", but the action result I use for this is called "Process Order". I've taken out the code in this function that is for the order form as it is not applicable. The section of my code for sending the email after the form is submitted is:
public ActionResult ProcessOrder(int? id)
{
//Send a confirmation email
var msgTitle = "Order Confirmation #" + orderDetail.OrderID;
var recipient = JohnDoe;
var fileAttach = //This is where I can't figure out how to attach//
var fileList = new string[] { fileAttach };
var errorMessage = "";
var OrderConfirmation = "Your order has been placed and is pending review." +
" Attached is a copy of your order.";
try
{
// Initialize WebMail helper
WebMail.SmtpServer = "abc.net";
WebMail.SmtpPort = 555;
WebMail.UserName = recipient;
WebMail.Password = "12345";
WebMail.From = "orders#samplecode.com";
// Send email
WebMail.Send(to: "orders#samplecode.com",
subject: msgTitle,
body: OrderConfirmation,
filesToAttach: fileList
);
}
catch (Exception ex)
{
errorMessage = ex.Message;
}
//5. Remove item cart session
Session.Remove(strCart);
return View("OrderSuccess");
}
I have been able to find very few articles on this issue using Rotativa and the ones I have found don't work for what I'm doing. Maybe Rotativa won't work for this, I'm hoping it does because I've designed my pdf report it generates from it, and not sure if doing it another way will screw up my formatting of it or not. As you can see at the bottom of the code, I return the view to an "OrderSuccess" page. When I try to implement the first code into the second code, it won't let me "return pdf" to execute the ActionAsPdf that generates the pdf when I do the "return View("OrderSuccess")". It only lets me do one or the other. If anybody knows how I can accomplish this, I need some help. I appreciate any suggestions or feedback. I'm pretty new to this so please be patient with me if I don't understand something.
Here is the updated code that fixed my problem and created the pdf, then attached it to an automated email once the order form was submitted:
public ActionResult ProcessOrder(int? id)
{
//1. Generate pdf file of order placed
string orderNum = "FulfillmentOrder" + orderDetail.OrderID + ".pdf";
var actionResult = new Rotativa.ActionAsPdf("OrderReportPDF", new { id = orderDetail.OrderID }) { FileName = orderNum };
var PdfAsBytes = actionResult.BuildFile(this.ControllerContext);
//2. Send confirmation email
var msgTitle = "Order Confirmation #" + orderDetail.OrderID;
var OrderConfirmation = "Your order has been placed and is pending review.<br />" +
" Attached is a copy of your order." +
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress("orders#samplecode.com");
mail.To.Add("orders#samplecode.com");
mail.Subject = msgTitle;
mail.Body = OrderConfirmation;
mail.IsBodyHtml = true;
//STREAM THE CONVERTED BYTES AS ATTACHMENT HERE
mail.Attachments.Add(new Attachment(new MemoryStream(PdfAsBytes), orderNum));
using (SmtpClient smtp = new SmtpClient("abc.net", 555))
{
smtp.Credentials = new NetworkCredential("orders#samplecode.com", "password!");
smtp.EnableSsl = true;
smtp.Send(mail);
}
}
//3. Remove item cart session
Session.Remove(strCart);
return View("OrderSuccess");
}
Thank you again to the people that helped and got me pointed in the right direction! Also, a quick shout out to #Drewskis who posted this answer in convert Rotativa.ViewAsPdf to System.Mail.Attachment where I was able to use it to solve my issue!

Converting to doc file in ASP.NET Core app and attaching doc file to email

I am trying to convert some data I get from my database in my ASP.NET application. So far I came across a very straight forward framework to do that called DocX.
https://www.nuget.org/packages/DocX/
So according to its API I decided that the best way to implement my task would be to first make a documents and save it to server. Then import it from server as stream and attach it to email. But I a doubtfull.
So I go:
var doc = DocX.Create("test.doc");
string f = "sdcdscdsc";
doc.InsertParagraph(f);
doc.Save();
Two things happen here:
1) First I get an exception FileNotFoundException: Could not load file or assembly 'System.IO.Packaging
2) Somehow... when I tried another framework for doing this DocumentCore (https://www.nuget.org/packages/sautinsoft.document/), I guess that installed a missing file and the Save() method started working and saving the file but the files where blank.
Honestly I would really appreciate on best practices to do this task. If anyone has come across similar task please share the methodology used.
The second part is a bit easier. I got the email part sorted but still got no idea how to attach the file. So far the code looks like this:
private static void SendMail()
{
var mailMessage = new MailMessage("xxxxxx#gmail.com", "xxxxxx#gmail.com");
mailMessage.Subject = "Tester ";
mailMessage.Body = "This is the message";
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.Credentials = new System.Net.NetworkCredential()
{
UserName = "xxxxxxxx#gmail.com",
Password = "xxxxxxxxx"
};
client.EnableSsl = true;
client.Send(mailMessage);
}
Overall it in bits and pieces and I would really appreciate some sharing of experience. Thank you very much.
Part 1 - create doc with content
Had to use DocXCore for ASP.NET Core app.
private void CreateDocument()
{
try
{
var doc = DocX.Create("mytest.docx");
doc.InsertParagraph("Hello my new message");
doc.Save();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Part 2 - sending email
private void SendMail()
{
var mailMessage = new MailMessage("xxxxx#gmail.com", "yzolxxxxxotarev#gmail.com");
mailMessage.Subject = "Tester ASP.NET Boat Inspector";
mailMessage.Body = "This is the message";
var contentPath = _env.ContentRootPath+#"\mytest.docx";
Attachment data = new Attachment(contentPath, MediaTypeNames.Application.Octet);
mailMessage.Attachments.Add(data);
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.Credentials = new System.Net.NetworkCredential()
{
UserName = "xxxxx#gmail.com",
Password = "xxxxx"
};
client.EnableSsl = true;
client.Send(mailMessage);
}
Works well.

Replace not working as expected, razor engine inserting unwanted periods

I have a class that uses the razor engine to generate html templates and there seems to be an issue where some links (anchors or images) have an additional period inserted into the address, usually at the www. part making the link unusable.
There doesn't appear to be any rhyme or reason as to when or where it does this, sometimes it works fine, other times several of the links have this issue.
So when I return the template as string to then send as an email I call replace like below:
var fixedTemplate = template.Replace("www..", "www.");
But this isn't working. I've never ran into this issue before. The strings are quite large, could this cause problems with the replace function?
How can I
a) Fix the razor engine so that these random periods are no longer added in links
Or
b) Find out why the replace function isn't replacing all of the occurrences.
A sample of the code called in my class below for completeness.
// nt = class associated with template
using (TemplateService templateService = new TemplateService())
{
string html = templateService.Parse(File.ReadAllText(nt.TemplateFilePath), nt, null, null);
var pm = new PreMailer.Net.PreMailer(html);
//inline css styles with premailer
Emailer.SendTestEmail(pm.MoveCssInline().Html, emailAddress, "Test Email: " + campaign.Title);
pm = null;
}
And the emailer code where replace is called
public static void SendTestEmail(string template, string emailAddress, string subject)
{
var updatedTemplate = template.Replace("www..", "www.");
var email = new MailMessage
{
Body = updatedTemplate,
Subject = subject,
IsBodyHtml = true,
From = new MailAddress("noreply#mydomain.com")
};
email.To.Add(emailAddress);
using (var smtpClient = new SmtpClient())
{
smtpClient.PickupDirectoryLocation = "M:\\Pickup";
smtpClient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
smtpClient.Send(email);
}
}

Sending bulk emails in c # .net windows application

My project is to send at least 100 mails an hour.
I have used for loop to retrieve emails from database and send email one by one.
But When I googled i find out that it will get time out after some time.So What is the method to use to hold the mail sending for a while and then restart the loop from hold position.Also,if the sending failed i should resend it.Should I use timer?
Please provide me any idea to complete this.
My sample code,
List<string> list = new List<string>();
String dbValues;
foreach (DataRow row in globalClass1.dtgrid.Rows)
{
//String From DataBase(dbValues)
dbValues = row["email"].ToString();
list.Add(dbValues);
}
using (System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient(mailserver, port))
{
client.Credentials = new System.Net.NetworkCredential(emailfrom, password);
client.EnableSsl = true;
MailMessage msg1 = new MailMessage();
foreach (string row in list)
{
if (row != null)
{
msg1=sendmail(row);
client.Send(msg1);
client.Dispose();
}
}}
Option 1
You can simply Add multiple recipients to To property of MailMessage:
var mail = new MailMessage();
mail.To.Add(new MailAddress("to#example.com"));
For example when you have a list that contains recipients, you can add theme all:
var mail = new MailMessage();
foreach (var item in list)
{
mail.To.Add(new MailAddress(item));
}
mail.From = new MailAddress("from#example.com");
mail.Subject = "Subject";
mail.Body = "Body";
client.Send(mail);
Option 2
If you don't want to set all addresses using To or Bcc you can can use a Task to send emails this way:
public void SendMails(List<string> list)
{
Task.Run(() =>
{
foreach (var item in list)
{
//Put all send mail codes here
//...
//mail.To.Add(new MailAddress(item));
//client.Send(mail);
}
});
}
Option 3
You can also use SendMailAsync to send mails.
Thanks to Panagiotis Kanavos to mention that this way is preferred instead of using Task.Run .
You should rather send them asynchronously using the pickup directory. Here is a good overview. http://weblogs.asp.net/gunnarpeipman/asp-net-using-pickup-directory-for-outgoing-e-mails
The SMTP server handles transient network connectivity issues, and retries periodically.

Sending email to multiple recipients via Google

I am working on an C# project where I am building my own SMTP server. It is basically working but I am now trying to get multiple recipients being sent but I am receiving an error.
I am getting the MX record from the senders domain and I am then using MX Record to try and send an email to multiple recipients. If I do two recipients with the same domain it works fine, if the two recipients have different domains, I then get the following response:
Failed to send email. General Exception: Error in processing. The server response was: 4.3.0 Multiple destination domains per transaction is unsupported. Please
There is nothing after please that's the end of the response.
Below is how I am getting the MX Record:
string[] mxRecords = mxLookup.getMXRecords(Classes.CommonTasks.getDomainFromEmail(domain));
public string[] getMXRecords(string domain)
{
DnsLite dl = new DnsLite(library);
ArrayList dnsServers = getDnsServers();
dl.setDnsServers(dnsServers);
ArrayList results = null;
string[] retVal = null;
results = dl.getMXRecords(domain);
if (results != null)
{
retVal = new string[results.Count];
int counter = 0;
foreach (MXRecord mx in results)
{
retVal[counter] = mx.exchange.ToString();
counter++;
}
}
return retVal;
}
Below is how I am sending the email.
if (mxRecords != null)
{
MailMessage composedMail = new MailMessage();
composedMail.From = new MailAddress(message.EmailFromAddress);
//MailAddressCollection test = new MailAddressCollection();
//composedMail.To = test;
composedMail = addRecipientsToEmail(composedMail, message.emailRecipients);
composedMail.Subject = message.subject;
composedMail.Body = message.EmailBody;
if (message.contentType.ToString().Contains("text/html"))
{
composedMail.IsBodyHtml = true;
}
SmtpClient smtp = new SmtpClient(mxRecords[0]);
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.Port = 25;
if (Configuration.emailConfig.useSmtpMaxIdleTime)
{
smtp.ServicePoint.MaxIdleTime = 1;
}
library.logging(methodInfo, string.Format("Sending email via MX Record: {0}", mxRecords[0]));
smtp.Send(composedMail);
updateEmailStatus(message.emailID, EmailStatus.Sent);
library.logging(methodInfo, string.Format("Successfully sent email ID: {0}", message.emailID));
}
else
{
string error = string.Format("No MX Record found for domain: {0}", domain);
library.logging(methodInfo, error);
library.setAlarm(error, CommonTasks.AlarmStatus.Warning, methodInfo);
}
This looks as if it is something that Google is restricting from being done but I can't find a way to work around out, other than to send the emails separately for each recipient.
If it's of any use, the two domains are google app domains.
Thanks for any help you can provide.
It seems you are not alone. Check this out.
:
"Based on my investigation and research, I believe what's happening is your system is connecting directly to the delivery server (aspmx.l.google.com). As this is the delivery server, it does not allow:
Delivery to accounts that are not provisioned on Google (i.e., unauthenticated relaying).
Delivery to multiple different domains within the same SMTP session.
The second one is the one that is important to us. As of the beginning of this month(May2012), adjustments were made to our server settings that mean that our delivery server is strictly enforcing the multiple-domain-not-allowed rule. There are two ways to get around this. The first is to send to separate domains on separate smtp sessions, and the second is to use smtp.gmail.com in place of aspmx.l.google.com."
http://productforums.google.com/forum/#!topic/apps/jEUrvTd1S_w
Sine you can send an email with a single recipient through google your issue is not in resolving the mx-record. The Mx record tells an IP-address but doesn't tell about the functionality/behavior of the service behind that ip.
You can resolve the mx-record, so far so good. But you don't need to to resolve the mx on your own as the smtp-client does it on your behalve, just supllying the hostname will do. But note that this was a great excersise to learn more about DNS. No time waste :-)
As far as I recall, sending mail through google in the way you intend you need a google account. Authenticate with the smtp-server with the credentials for that account can open a new perspective

Categories