I have a console application that sends emails to several (12 currently) different email groups. The process loops through and each time creates a different excel workbook, saves the workbook, then sends an email with this workbook attached.
This process ran great for several months. Now, the program will make it through 2 emails, then it will throw an exception for Failure sending mail. I have found the inner exception is Unable to read data from the transport connection: net_io_connectionclosed
The workbooks are created via 2 SQL stored procs. Even when the email fails, the workbooks are created and can be opened so I don't think it has anything to do with the SQL involved.
I have seen several other SO issues for similar issues, but since my process works for 2, fails for 1, works for 2, fails for 1.... I believe my issue is different than a simple port or credentials issue.
Here is the code I have before loop to declare the SmtpClient
SmtpClient client = new SmtpClient("intmail.MyDomain.net", 25);
NetworkCredential cred = new NetworkCredential("myEmailAddress#email.com", "");
client.Credentials = cred; // Send our account login details to the client.
client.EnableSsl = false; // Read below.
Here is my code inside the loop for creating email, attaching workbook, and sending.
MailMessage msg = new MailMessage();
Attachment xls01 = new Attachment(filePath);
string emailTo = ClientEmail;
string[] emailTos = emailTo.Split(new char[] { ';' });
foreach (string To in emailTos)
{
msg.To.Add(To);
Console.WriteLine(To);
}
msg.From = new MailAddress("myEmailAddress#email.com");
//msg.CC.Add(new MailAddress("myEmailAddress#email.com"));
msg.Subject = ClientName + reportMonth + " " + reportYear;
msg.Body = "Attached is report for period ending on the last day of " + reportMonth + " " + reportYear + ".\r\nAlso attached are the 13 month trends.";
msg.Attachments.Add(xls01);
try
{
client.Send(msg);
}
catch (Exception ex)
{
Console.WriteLine(ex); //Should print stacktrace + details of inner exception
if (ex.InnerException != null)
{
Console.WriteLine("InnerException is: {0}", ex.InnerException);
}
}
Most likely you are hitting smtp server antispam filter when you sending messages one right after another. Try to space them apart in time and make 3 attempts for each send. Obviously you should not stop if any one send is failed, you should go through all 12.
Related
This is my first time asking a question on StackOverflow, so let me know if you need more clarification. I am attempting to send emails with an attachment to users of a system, however I am having difficulty cleaning up the attachments on the file system after the messages are sent.
Background
I am using SSIS to compile a listing of email recipients and message content from a SQL database, then using a Script Component to do the actual email sending with C#. I am more of a DBA/Project Manager by role, and know enough coding to do some small things, but it has been quite some years since I did any .Net coding on a daily basis.
Each time I run the routine, the attachment files (Excel files in this case) are created successfully in a dedicated directory, then the emails are generated using those attachments and placed in a pickup folder. As each email is created and sent, I want to delete the attachment from its directory, but I get this error:
The process cannot access the file 'D:\mailtest\{filename}.xls' because it is being used by another process.
The specific file that it errors on is different each time, and of the ~3000 emails that are to be generated, it fails at around the 1200-1500 emails mark.
Code
//Create message
using (MailMessage msg = new MailMessage())
{
msg.To.Add(new MailAddress(EmailRecipient));
if (Row.Cc.Length > 0)
{
msg.CC.Add(new MailAddress(Row.Cc));
}
if (Row.Bcc.Length > 0)
{
msg.Bcc.Add(new MailAddress(Row.Bcc));
}
msg.From = new MailAddress(EmailSender);
msg.Subject = MessageSubject;
msg.Body = MessageBody +
"\n" +
"\n" +
this.Variables.EmailFooter;
msg.IsBodyHtml = true;
msg.BodyEncoding = System.Text.Encoding.UTF8;
//Add attachment data
if (File.Exists(attachmentPath))
{
Attachment data = new Attachment(attachmentPath);
data.ContentDisposition.FileName = "Expiring Training.xls";
msg.Attachments.Add(data);
}
if (this.Variables.UsePickupDirectory) //Drops items into pickup directory
{
SmtpClient client = new SmtpClient(SMTPEndPoint, SMTPPort)
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory,
PickupDirectoryLocation = this.Variables.PickupDirectory,
Credentials = new NetworkCredential(UserName, Password)
};
try
{
client.Send(msg);
}
catch (Exception e)
{
//Debug.WriteLine(e);
Row.ErrorMessage = e.Message;
}
finally
{
msg.Dispose(); //Release file
}
}
else //Send to SMTP Server
{
SmtpClient client = new SmtpClient(SMTPEndPoint, SMTPPort)
{
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential(UserName, Password)
};
try
{
client.Send(msg);
}
catch (Exception e)
{
//Debug.WriteLine(e);
Row.ErrorMessage = e.Message;
}
finally
{
//Add sleep to prevent sending more than 10 emails per second
System.Threading.Thread.Sleep(100);
msg.Dispose(); //Release file
}
}
}
//Remove attachment file
if (File.Exists(attachmentPath))
{
File.Delete(attachmentPath);
}
Things I've Tried
Initially, I did not have the using block. I saw this suggestion on a similar SO question, but adding it here seems to make no difference.
I've added the Dispose() to the finally block of each path (only the pickup directory is used in this case), which I understand should release all locks on the files used as attachments.
Without either of those things, it fails on the first file encountered, which leads me to believe it is working, but only for a while, and then fails suddenly at a random point during the execution.
The file specified in the error is not showing in process explorer when I search for it, so maybe it is released quickly after the error, so that I cannot search in time?
I tried moving the "Delete" functionality to a separate process entirely, running directly after all emails had been sent, but the same message would appear anyway.
I'd be thankful for any advice if anyone has a clue what could be happening.
New info
Adding some extra error handling did improve things, but didn't totally fix it. I've had several runs make it all the way through successfully, and whenever there was an error, it was only on 1 out of the ~3000 files. It did show the same error, though: "The process cannot access the file 'D:\mailtest{...}.xls' because it is being used by another process." That error was from the File.Delete line. It makes me wonder how just by adding more stuff it errors less. Is the sending and deleting happening so fast that it's stepping on its own toes? And throwing stuff in slows it down enough that it's able to keep up?
New Info 2
I took Jamal's advice and added a 500ms delay between send and delete, but only if the first delete attempt failed. So far no errors on 10 straight runs, whereas it was failing every single run in some way prior to adding it. However, the FireInformation message never appeared in the output window, leading me to think it never reached that block, so I'm not sure why adding it seems to work.
//Remove attachment file
if (File.Exists(attachmentPath))
{
try
{
File.Delete(attachmentPath);
}
catch
{
try
{
this.ComponentMetaData.FireInformation(0, "Delete failed", "Trying Delete again after 500ms", "", 0, fireAgain);
System.Threading.Thread.Sleep(500);
File.Delete(attachmentPath);
}
catch (Exception e)
{
Row.ErrorMessage = e.Message;
this.ComponentMetaData.FireInformation(e.HResult, e.Source, e.Message, e.HelpLink, 0, fireAgain);
}
}
}
string email ="sample#gmail.com";
attachment = path + "/" + filename;
Application.OpenURL ("mailto:" +
email+"
?subject=EmailSubject&body=EmailBody"+"&attachment="+attachment);
In the above code, attachment isn't working. Is there any other alternative to add attachments using a mailto: link in C#?
mailto: doesn't officially support attachments. I've heard Outlook 2003 will work with this syntax:
<a href='mailto:name#domain.com?Subject=SubjTxt&Body=Bod_Txt&Attachment=""C:\file.txt"" '>
Your problem has already been answered:
c-sharp-mailto-with-attachment
You can use the System.Net.Mail which has the MailMessage.Attachments Property. Something like:
message.Attachments.Add(new Attachment(yourAttachmentPath));
OR
You can try like this:
using SendFileTo;
namespace TestSendTo
{
public partial class Form1 : Form
{
private void btnSend_Click(object sender, EventArgs e)
{
MAPI mapi = new MAPI();
mapi.AddAttachment("c:\\temp\\file1.txt");
mapi.AddAttachment("c:\\temp\\file2.txt");
mapi.AddRecipientTo("person1#somewhere.com");
mapi.AddRecipientTo("person2#somewhere.com");
mapi.SendMailPopup("testing", "body text");
// Or if you want try and do a direct send without displaying the
// mail dialog mapi.SendMailDirect("testing", "body text");
}
}
}
The above code uses the MAPI32.dll.
Source
It probably won't attach the document because you are at the liberty
of the email client to implement the mailto protocol and include
parsing for the attachment clause. You may not know what mail client
is installed on the PC, so it may not always work - Outlook certainly
doesn't support attachments using mailto.
A better way to handle this is to send the mail on the server using System.Net.Mail.Attachment.
public static void CreateMessageWithAttachment(string server)
{
// Specify the file to be attached and sent.
// This example assumes that a file named Data.xls exists in the
// current working directory.
string file = "data.xls";
// Create a message and set up the recipients.
MailMessage message = new MailMessage(
"jane#contoso.com",
"ben#contoso.com",
"Quarterly data report.",
"See the attached spreadsheet.");
// Create the file attachment for this e-mail message.
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
// Add the file attachment to this e-mail message.
message.Attachments.Add(data);
//Send the message.
SmtpClient client = new SmtpClient(server);
// Add credentials if the SMTP server requires them.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
try
{
client.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in CreateMessageWithAttachment(): {0}", ex.ToString());
}
data.Dispose();
}
using following code i have reading msg from my hotmail account . But sometimes the following error coming . -ERR Exceeded the login limit for a 15 minute period. Reduce the frequency of requests to the POP3 server . can anyone tell me whats the reason for this ? Is that server problem or anything else ? other than pop3 anyother protocol can we use for hotmail?
public string hotmail(string username, string password)
{
string result = "";
string str = string.Empty;
string strTemp = string.Empty;
try
{
TcpClient tcpclient = new TcpClient();
tcpclient.Connect("pop3.live.com", 995);
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
sslstream.AuthenticateAsClient("pop3.live.com");
System.IO.StreamWriter sw = new StreamWriter(sslstream);
System.IO.StreamReader reader = new StreamReader(sslstream);
strTemp = reader.ReadLine();
sw.WriteLine("USER" + " " + username);
sw.Flush();
strTemp = reader.ReadLine();
sw.WriteLine("PASS" + " " + password);
sw.Flush();
strTemp = reader.ReadLine();
string[] numbers = Regex.Split(strTemp, #"\D+");
int a = 0;
foreach (string value in numbers)
{
if (!string.IsNullOrEmpty(value))
{
int i = int.Parse(value);
numbers[a] = i.ToString();
a++;
}
}
sw.WriteLine("RETR" + " " + numbers[0]);
sw.Flush();
strTemp = reader.ReadLine();
while ((strTemp = reader.ReadLine()) != null)
{
if (strTemp == ".")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
sw.WriteLine("Quit ");
sw.Flush();
result = str;
return result;
}
Catch ( Exception ex)
{}
return result;
}
thanks in advance ..
Any other protocol you can use? Yes, hotmail/outlook.com now supports IMAP.
But the issue with the code here seems to be that you're creating a new TcpClient every time you run this. If you're running it many times in in a row, Outlook.com/Hotmail will eventually complain. It's as if you've got tons of clients from a single source connecting to their server, which is, when it's not testing code, often a sign of email abuse.
TcpClient tcpclient = new TcpClient(); // Hello, new.
tcpclient.Connect("pop3.live.com", 995);
If you've got a lot to do on the server, keep a single connection active longer, and close it up when you're done.
Every time you run the code in your question, you're creating (and not tcpclient.Close()-ing) a connection to pop3.live.com. I usually only get this error when I've had a lot of connections that don't close properly due to errors when I'm messing with my code.
MSDN actually has a decent example for TcpClient, but you might be more interested in another example from SO here. Check out how it uses using, and nests a loop inside.
using (TcpClient client = new TcpClient())
{
client.Connect("pop3.live.com", 995);
while(variableThatRepresentsRunning)
{
// talk to POP server
}
}
By the way, the best advice I can give here is to tell you not to reinvent the wheel (unless you're just having fun playing with the POP server. Throwing commands via TCP can be lots of fun, especially with IMAP).
OpenPop.NET is a great library to handle POP requests in C#, includes a good MIME parser, and, if you're still working on this, should speed you along quite a bit. Its examples page is excellent.
Go to the mail inbox , you may get mail regarding this and accept it. Otherwise Try to give the request after some time. Because google having some restriction to read mail using pop settings.
I've recently designed a program in C# that will pull information from SQL databases, write an HTML page with the results, and auto-email it out. I've got everything working [sporadically], the problem I'm having is that I seem to be crashing our company's exchange server. After the first few successful runs of the program, I'll start getting this exception:
Base exception: System.Net.Mail.SmtpException: Insufficient system storage. The server response was: 4.3.1 Insufficient system resources
I'm wondering if I should be calling some sort of Dispose()-like method in my mailing? Or if there is any other apparent reason that I would be causing the mail system to stop responding? This affects all clients in our company, not just my code.
This is Exchange 2010, and my code is compiled against .NET 3.5. My attachments are typically 27kb. If I log into the exchange server, it seems that messages just stick in a queue indefinitely. Clearing out the queue (remove without sending NDR) and rebooting the server will get it going again.
The mailing portions look like this (username, password, and address changed):
public void doFinalEmail()
{
List<string> distList = new List<string>();
string distListPath = Environment.CurrentDirectory + "\\DistList.txt";
string aLine;
logThat("Attempting email distribution of the generated report.");
if (File.Exists(distListPath))
{
FileInfo distFile = new FileInfo(distListPath);
StreamReader distReader = distFile.OpenText();
while (!String.IsNullOrEmpty(aLine = distReader.ReadLine()))
{
distList.Add(aLine);
}
}
else
{
logThat("[[ERROR]]: Distribution List DOES NOT EXIST! Path: " + distListPath);
}
MailMessage msg = new MailMessage();
MailAddress fromAddress = new MailAddress("emailaddresshere");
msg.From = fromAddress;
logThat("Recipients: ");
foreach (string anAddr in distList)
{
msg.To.Add(anAddr);
logThat("\t" + anAddr);
}
if (File.Exists(Program.fullExportPath))
{
logThat("Attachment: " + Program.fullExportPath);
Attachment mailAttachment = new Attachment(Program.fullExportPath);
msg.Attachments.Add(mailAttachment);
string subj = "Company: " + Program.yestFileName;
msg.Subject = subj;
msg.IsBodyHtml = true;
msg.BodyEncoding = System.Text.Encoding.UTF8;
sendMail(msg);
}
else
{
logThat("[[ERROR]]: ATTACHMENT DOES NOT EXIST! Path: " + Program.fullExportPath);
}
}
public void sendMail(MailMessage msg)
{
try
{
string username = "user"; //domain user
string password = "pass"; // password
SmtpClient mClient = new SmtpClient();
mClient.Host = "192.168.254.11";
mClient.Credentials = new NetworkCredential(username, password);
mClient.DeliveryMethod = SmtpDeliveryMethod.Network;
mClient.Send(msg);
}
catch (Exception oops)
{
string whatHappened = String.Format("Company: \r\nFailure in {0}! \r\n\r\nError message: {1} \r\nError data: {2} \r\n\r\nStack trace: {3} \r\n\r\nBase exception: {4} \r\nOccuring in method: {5} with a type of {6}\r\n", oops.Source, oops.Message, oops.Data, oops.StackTrace, oops.GetBaseException(), oops.TargetSite, oops.GetType());
logThat(whatHappened);
Environment.Exit(1);
}
}
This error can happen when:
The exchange server is out of disk space.
The recipient mailbox is out of disk space.
It is more common to run into issue #2 than issue #1.
Here is a list of Exchange Status Codes and their meanings.
To narrow down the issue definitively, you could swap in a different mail client like aspNetEmail (you can get an eval version to test), it wouldn't take but a few lines of code. If the problem persists, it is on the server; if not, it is on the client. I would strongly suspect this is a problem on the server, however, as when the client closes the connection and the message is sent, the server should really not be holding any resources as a result of that connection. You could verify this by looking at your SMTP logs and making sure there was no SMTP error when the connection was closed.
If this is indeed a problem on the server (the SMTP log shows clean disconnection and the problem is replicable with an alternate client), then I would log onto the server (if you can get access), and watch the disk space as jeuton suggests.
In exchange 2007 the c: (system drive) needs about 4GB of free disk space. This was our problem. Increment the drive and the mails will flow again.
Currently I am using the below method to open the users outlook email account and populate an email with the relevant content for sending:
public void SendSupportEmail(string emailAddress, string subject, string body)
{
Process.Start("mailto:" + emailAddress + "?subject=" + subject + "&body="
+ body);
}
I want to however, be able to populate the email with an attached file.
something like:
public void SendSupportEmail(string emailAddress, string subject, string body)
{
Process.Start("mailto:" + emailAddress + "?subject=" + subject + "&body="
+ body + "&Attach="
+ #"C:\Documents and Settings\Administrator\Desktop\stuff.txt");
}
However this does not seem to work.
Does anyone know of a way which will allow this to work!?
Help greatly appreciate.
Regards.
If you want to access the default email client then you can use MAPI32.dll (works on Windows OS only).
Take a look at the following wrapper:
http://www.codeproject.com/KB/IP/SendFileToNET.aspx
Code looks like this:
MAPI mapi = new MAPI();
mapi.AddAttachment("c:\\temp\\file1.txt");
mapi.AddAttachment("c:\\temp\\file2.txt");
mapi.AddRecipientTo("person1#somewhere.com");
mapi.AddRecipientTo("person2#somewhere.com");
mapi.SendMailPopup("testing", "body text");
// Or if you want try and do a direct send without displaying the mail dialog
// mapi.SendMailDirect("testing", "body text");
mailto: doesn't officially support attachments. I've heard Outlook 2003 will work with this syntax:
<a href='mailto:name#domain.com?Subject=SubjTxt&Body=Bod_Txt&Attachment=""C:\file.txt"" '>
A better way to handle this is to send the mail on the server using System.Net.Mail.Attachment.
public static void CreateMessageWithAttachment(string server)
{
// Specify the file to be attached and sent.
// This example assumes that a file named Data.xls exists in the
// current working directory.
string file = "data.xls";
// Create a message and set up the recipients.
MailMessage message = new MailMessage(
"jane#contoso.com",
"ben#contoso.com",
"Quarterly data report.",
"See the attached spreadsheet.");
// Create the file attachment for this e-mail message.
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
// Add the file attachment to this e-mail message.
message.Attachments.Add(data);
//Send the message.
SmtpClient client = new SmtpClient(server);
// Add credentials if the SMTP server requires them.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
try {
client.Send(message);
}
catch (Exception ex) {
Console.WriteLine("Exception caught in CreateMessageWithAttachment(): {0}",
ex.ToString() );
}
data.Dispose();
}
Does this app really need to use Outlook? Is there a reason for not using the System.Net.Mail namespace?
If you really do need to use Outlook ( and I would not recommend it because then you're basing your app on 3rd party dependencies that are likely to change) you will need to look into the Microsoft.Office namespaces
I'd start here:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.aspx
Try this
var proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = string.Format("\"{0}\"", Process.GetProcessesByName("OUTLOOK")[0].Modules[0].FileName);
proc.StartInfo.Arguments = string.Format(" /c ipm.note /m {0} /a \"{1}\"", "someone#somewhere.com", #"c:\attachments\file.txt");
proc.Start();