SmtpClient.Dispose throws System.IO.IOException - c#

My code sends e-mails like this:
private void DispatchMail(MailMessage mailMessage)
{
using (var smtpClient = new SmtpClient())
{
smtpClient.Send(mailMessage);
}
}
The MailMessage instances are very simple with a HTML body and no attachments.
The configuration of the SmtpClient is in web.config like this:
<system.net>
<mailSettings>
<smtp from="yourmail#gmail.com">
<network host="mailprovider.org" port="587" enableSsl="true" userName="username#host" password="secret" />
</smtp>
</mailSettings>
</system.net>
Whenever the method DispatchMail is called, the mail is actually sent to the recipient, however I get an exception in the implicitly called SmtpClient.Dispose method.
Exception: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.Security._SslStream.StartFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.TlsStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Mail.SmtpPooledStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.ForceCleanup()
at System.Net.ConnectionPoolManager.CleanupConnectionPool(ServicePoint servicePoint, String groupName)
at System.Net.Mail.SmtpClient.Dispose(Boolean disposing)
at System.Net.Mail.SmtpClient.Dispose()
at QueuedMailDispatcherService.DispatchMail(MailMessage mailMessage)
Inner exception: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
Is this a bug in the .NET Framework 4.5.2 or am I mismanaging the life-cycle of the SMTP client?
The SMTP server in question responds as "Microsoft ESMTP MAIL Service".
Update
First I dismissed this problem since it only happened on my machine, but then it happened on the production machine running same code but with release configuration.
Since this error happens intermittently I have decided to modify the method to use a two-level exception handling strategy where any exception occurring when Dispose is called is ignored.
When I was able to catch this error and step through the framework source it seemed like the offset parameter was corrupted (it was several MB higher than the buffer.Length) somewhere between System.Net.Sockets.NetworkStream.Read and System.Net.Sockets.Socket.Receive. However further inspection of the source does not imply that the offset would be changed. In fact System.Net.Security._SslStream.StartFrameHeader sets offset to 5 higher up in the call stack. This leads me to believe that one of the following things happened:
The debugged machine level code was not matching the source I stepped through in Visual Studio
Some kind of memory corruption (however the problem has persisted through one reboot and on two different machines both in debug and release configuration)
I was actually debugging two different threads without realizing it
There is some kind of difficult rare race condition going on
There is some kind of optimization going wrong, maybe in combination with the race condition
The SMTP server implementation or the network transmission is not reliable during SMTP Quit, however it is a well known SMTP server software and I cannot see why this problem would be intermittent also it does not explain the out of bound offset value.

Try the below sample:
using System.Net.Mail;
private void DispatchMail(string to)
{
var mail = new MailMessage
{
Subject = "subject",
From = new MailAddress(#"sender email", #"sender name")
};
mail.To.Add(to);
mail.Body = "your message body";
var smtp = new SmtpClient(#"smtp mail server address");
smtp.Port = 587;
smtp.Credentials = new System.Net.NetworkCredential("username", "password");
smtp.EnableSsl = true;
smtp.Send(mail);
mail.Dispose();
smtp.Dispose();
}

you can do something like this
var fromAddress = new MailAddress("fromAddress", "My Name");
var toAddress = new MailAddress("gtoAddress ", "Mr Test");
const string fromPassword = "fromPassword";
string subject = "hello";
string body = "how are you doing?";
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword),
Timeout = 20000
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body
})
{
smtp.Send(message);
}
and enable less secure apps on your Gmail account here

Related

Error trying to use MailKit to send Email "A connection attempt failed because the connected party did not properly respond after a period of time"

Getting an error when I try to send emails using MailKit. Using port 587 and host is a Barracuda server. Email still manages to send but breaks at client.Send(mail) and gives this error below.
Does anyone know what I'm missing or doing wrong? I can provide more code if needed.
Send mail code:
client.Connect(_SMTPOptions.Host, _SMTPOptions.Port, SecureSocketOptions.StartTls);
client.Timeout = 1000;
client.Send(mail);
client.Disconnect(true);
Add attachement code (if this matters):
bytes = bytes + document.Bytes.Length;
Stream stream = new MemoryStream(document.Bytes);
streamlist.Add(stream);
var attachment = new MimePart("application","pdf")
{
Content = new MimeContent(stream, ContentEncoding.Default),
ContentDisposition = new MimeKit.ContentDisposition(MimeKit.ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName(order.OrderNumber + "_" + document.DocumentType + "_" + document.IntDocID + ".pdf")
};
builder.Attachments.Add(attachment);
Error Message:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
StackTrace:
StackTrace: at MailKit.Net.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Stream.Read(Span 1 buffer)
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory 1 buffer)
at System.Net.Security.SslStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at MailKit.Net.Smtp.SmtpStream.ReadAheadAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponseAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponse(CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpClient.DataAsync(FormatOptions options, MimeMessage message, Int64 size, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.SendAsync(FormatOptions options, MimeMessage message, MailboxAddress sender, IList`1 recipients, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.Send(FormatOptions options, MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.MailTransport.Send(MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
The problem is likely to be this line:
client.Timeout = 1000;
You are telling MailKit to throw an exception after 1000 milliseconds (aka 1 second) if it cannot read from (or write to) a socket within that time period.
The default timeout that MailKit uses is 2 minutes (2 * 60 * 1000).

How do I fix System.IO.IOException from SerialPort.Write in C#?

I have a virtual COM device (USB to UART) that I am attempting to command using C# SerialPort. When I call the Write or WriteLine methods I get the following stack trace:
Exception (System.IO.IOException): The I/O operation has been aborted because of either a thread exit or an application request.
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult)
at System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
at System.IO.Ports.SerialPort.Write(String text)
I've confirmed port, baud rate, parity, and handshake with both the device documentation and by successfully communicating through PuTTY, so the issue must be with my C# code.
_serialPort = new SerialPort(commId, 9600, Parity.None, 8, StopBits.One)
{
Handshake = Handshake.XOnXOff,
ReadTimeout = 5000,
WriteTimeout = 5000,
NewLine = "\r", //added during debug
DtrEnable = true, //added during debug
RtsEnable = true //added during debug
};
_serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
_serialPort.Open();
_serialPort.DiscardInBuffer(); //added during debug
_serialPort.DiscardOutBuffer(); //added during debug
_serialPort.Write("echo");
_serialPort.WriteLine("echo");

C# SQL Server CLR Request error on functions GET and POST

I followed the GitHub documentation to implement the http requests with the CURL extension, work in SQL Server 2008 R2, Visual Studio 2010 and .NET 3.5.
I managed to compile and sign correctly the .dll in visual studio, to then create the schemas and functions in SQL Server, since everything works correctly, I can perform GET and POST from SQL Server, however, when wanting to perform a GET or a POST at SABA API, it generates a series of errors.
A .NET Framework error occurred during execution of user-defined
routine or aggregate "XGET": System.Net.WebException: The underlying
connection was closed: An unexpected error occurred on a send. --->
System.IO.IOException: Received an unexpected EOF or 0 bytes from the
transport stream. System.IO.IOException: at
System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset,
Int32 count) at System.Net.Security.SslState.StartReadFrame(Byte[]
buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer,
AsyncProtocolRequest asyncRequest) at
System.Net.Security.SslState.CheckCompletionBeforatextReceive(ProtocolTokat
message, AsyncProtocolRequest asyncRequest) at
System.Net.Security.SslState.StartSatdBlob(Byte[] incoming, Int32
count, AsyncProtocolRequest asyncRequest) at
System.Net.Security.SslState.ForceAuthattication(Boolean receiveFirst,
Byte[] buffer, AsyncProtocolRequest asyncRequest) at
System.Net.Security.SslState.ProcessAuthattication(LazyAsyncResult
lazyResult) at
System.Net.TlsStream.CallProcessAuthattication(Object state) at
System.Threading.ExecutionContext.runTryCode(Object userData) at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode
code, CleanupCode backoutCode, Object userData) at
System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Net.TlsStream.ProcessAuthattication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32
size) at System.Net.ConnectStream.WriteHeaders(Boo ...
System.Net.WebException: at
System.Net.WebCliatt.DownloadDataInternal(Uri address, WebRequest&
request) at System.Net.WebCliatt.DownloadString(Uri address) ...
This is the code of the Assembly
using Microsoft.SqlServer.Server;
using System;
using System.Data.SqlTypes;
using System.Net;
using System.Threading;
public static class Curl
{
[SqlFunction]
[return: SqlFacet(MaxSize = -1)]
public static SqlChars Get(SqlChars H, SqlChars url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
var client = new WebClient();
AddHeader(H, client);
return new SqlChars(
client.DownloadString(
Uri.EscapeUriString(url.ToSqlString().Value)
).ToCharArray());
}
[SqlProcedure]
public static void Post(SqlChars H, SqlChars d, SqlChars url)
{
var client = new WebClient();
AddHeader(H, client);
if (d.IsNull)
throw new ArgumentException("You must specify data that will be sent to the endpoint", "#d");
var response =
client.UploadString(
Uri.EscapeUriString(url.ToSqlString().Value),
d.ToSqlString().Value
);
SqlContext.Pipe.Send("Request is executed. " + response);
}
[SqlProcedure]
public static void PostWithRetry(SqlChars H, SqlChars d, SqlChars url)
{
var client = new WebClient();
AddHeader(H, client);
if (d.IsNull)
throw new ArgumentException("You must specify data that will be sent to the endpoint", "#d");
int i = RETRY_COUNT;
string response = "";
do try
{
response =
client.UploadString(
Uri.EscapeUriString(url.ToSqlString().Value),
d.ToSqlString().Value
);
i = -1;
break;
}
catch (Exception ex)
{
SqlContext.Pipe.Send("Error:\t" + ex.Message + ". Waiting " + DELAY_ON_ERROR + "ms.");
i--;
Thread.Sleep(DELAY_ON_ERROR);
}
while (i > 0);
if (i == -1)
SqlContext.Pipe.Send("Request is executed." + response);
}
static readonly int RETRY_COUNT = 3;
static readonly int DELAY_ON_ERROR = 50;
public static bool IsNullOrWhiteSpace(this string theString)
{
if (theString == null)
{
return false;
}
if (theString.Trim() == string.Empty)
{
return false;
}
return true;
}
private static void AddHeader(SqlChars H, WebClient client)
{
if (!H.IsNull)
{
string header = H.ToString();
if (!IsNullOrWhiteSpace(header))
client.Headers.Add(HttpRequestHeader.UserAgent, header);
}
}
};
And this how to use in SQL Query
declare #hkey nvarchar(4000) = 'SabaCertificate: 31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C';
declare #endpoint nvarchar(1000) = 'https://libertad-api.sabacloud.com/v1/location?count=10&startPage=1';
select curl.xget(#hkey, #endpoint)
I already test it in PostMan, entering the Header of SabaCertificate, and if it throws a result at me, however, when the certificate is not correct it also throws a response and it is not shown.
Bad Request Example:
{"errorCode":123,"errorMessage":"Invalid or expired Certificate"}
But it also does not give me the answer of the certificate error, that I have to change in my WebClient for this to work.
Added to this I think the certificate is too big because sometimes I get this error:
The identifier that starts with 'SabaCertificate:
31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C'
is too long. Maximum length is 128.
One definite problem in the code is a slight change you made to the original code. In your AddHeader method you have the following line:
client.Headers.Add(HttpRequestHeader.UserAgent, header);
You need to remove the HttpRequestHeader.UserAgent because the code is now creating a "UserAgent" header with a value of whatever you pass in, which is "SabaCertificate: 31336132....".
You will also need to change the security protocols that you are setting as they are not correct. You should try:
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072; // TLS 1.2
Since you are using .NET 3.5 via SQL Server 2008 R2, you cannot specify SecurityProtocolType.Tls12 since that value had not yet been added to the enum in Framework Version 3.5, so you have to use the numeric value as shown above. Please keep in mind that the actual ability to do the security protocol is a function of the underlying OS, so it is possible that an older version of Windows / Windows Server does not support TLS 1.2, or might need a registry setting changed in order to do so. You will have to play around with that if you continue to get similar errors from System.Net.TlsStream.
Also, the following error:
The identifier that starts with 'SabaCertificate: 31336...30FDB06C' is too long. Maximum length is 128.
is from user-error. An "identifier" is an item name within SQL Server (objects, Logins, variables, etc). This means that you are doing something different (and wrong) when that error happens, but I can't see how it could be coming from your code, at least not the Get method, as that has no internal interaction with the database.

SmtpClient "Unable to read data from transport connection" only happens after x amount of emails are sent

Edit: Things I have tried
On the server running smtp in smpt virtual server I have set IP
address to specific IP and to "all unassigned", in the Access tab of
SMTP Virtual Service, under relay tab, I have added all the IPs to
grant list along with 127.0.0.1
client.ServicePoint.MaxIdleTime = 100;
moved the using (creating of client) to inside of the for loop
Still same problem, 300 seems to be the magic number before it craps out
I have a very extremely weird problem that I have been trying to solve for past week. My task is simple, "send bulk mail", so I created a very simple exe that will send bunch of emails to a gmail account.
After about sending 280, the sending fails with the following error: I have tried both port 587 and 25 and the problem happens on both ports
System.Net.Mail.SmtpException: Failure sending mail. --->
System.IO.IOException: Unable to read data from the transport connection:
net_io_connectionclosed.
at System.Net.Mail.SmtpReplyReaderFactory.ProcessRead(Byte[] buffer, Int32
offset, Int32 read, Boolean readLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLines(SmtpReplyReader caller,
Boolean oneLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLine(SmtpReplyReader caller)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
Now I will note that if i run the exe again RIGHT after it fails and i try to send ONE email, i get the same error so the issue does not seem to be a coding issue. This is being sent on VPS running windows 2016 and SmarterMail 16 smtp server.
If i wait about an hour and try to send again, i can successfully send another 280. It seems there is some sort of throttling happening somewhere (I already turned off all the throttlings in SmarterMail).
What is weird is, right after it fails, if i use a service like https://www.smtper.net/ and use the same exact settings as i am using in my exe, then the email goes through with out any errors. I am not sure if this is a smtp error, some setting on windows 2016 that wont allow more than x an hour etc.
Below is my actual exe code, as you can see its extremely simple example
static void Main(string[] args)
{
Console.WriteLine("How many emails do you want to send?");
var emailCount = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("How many seconds do you want to delay between each send");
var delay = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("What email address do you want to send to");
var toEmailAddress = Console.ReadLine();
Console.WriteLine($"Sending out {emailCount} with {delay} second delay to {toEmailAddress}");
using (var client = new SmtpClient(ConfigurationManager.AppSettings["SmtpServer"]))
{
for (int i = 1; i <= emailCount; i++)
{
try
{
var body = "this is a test message";
var userName = ConfigurationManager.AppSettings["Username"];
var password = ConfigurationManager.AppSettings["Password"];
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(userName, password);
client.Port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
//client.EnableSsl = true;
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(ConfigurationManager.AppSettings["FromEmail"]);
mailMessage.To.Add(toEmailAddress);
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
mailMessage.Subject = ConfigurationManager.AppSettings["Subject"];
client.Send(mailMessage);
if (delay > 0)
{
Console.WriteLine("Sleeping...");
Thread.Sleep(delay * 1000);
}
Console.WriteLine($"Email number {i} was sent successfully.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to send {i} of {emailCount}");
Console.WriteLine(ex.ToString());
}
}
}
Console.WriteLine("Done...press any key to exit");
Console.ReadKey();
}

smtp exception "failure sending mail"

I am making an SMTP mail application with C#.Net. It is working ok for Gmail settings, but I have to work it for a connection to VSNL. I am getting an exception: "Failure sending mail"
My settings seem perfect. What is the problem? Why am I getting the exception?
MailMessage mailMsg = new MailMessage();
MailAddress mailAddress = new MailAddress("mail#vsnl.net");
mailMsg.To.Add(textboxsecondry.Text);
mailMsg.From = mailAddress;
// Subject and Body
mailMsg.Subject = "Testing mail..";
mailMsg.Body = "connection testing..";
SmtpClient smtpClient = new SmtpClient("smtp.vsnl.net", 25);
var credentials = new System.Net.NetworkCredential("mail#vsnl.net", "password");
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = credentials;
smtpClient.Send(mailMsg);
I am getting an exception following...
System.IO.IOException: Unable to read data from the transport connection: net_io_connectionclosed.
at System.Net.Mail.SmtpReplyReaderFactory.ProcessRead(Byte[] buffer, Int32 offset, Int32 read, Boolean readLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLines(SmtpReplyReader caller, Boolean oneLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLine(SmtpReplyReader caller)
at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
Check the InnerException of the exception, should tell you why it failed.
Try wrapping the Send call in a try catch block to help identify the underlying problem.
e.g.
try
{
smtpClient.Send(mailMsg);
}
catch (Exception ex)
{
Console.WriteLine(ex); //Should print stacktrace + details of inner exception
if (ex.InnerException != null)
{
Console.WriteLine("InnerException is: {0}",ex.InnerException);
}
}
This information will help identify what the problem is...
Make sure your Anti Virus is blocking sending mails. In my case McAfee Access protection Rules were blocking sending mails, untick blocks and reports.
I used some but i am checking only this if send mail fails:
default value is false;
but it can't be change to true;
smtpClient.Port = smtpServerPort;
smtpClient.UseDefaultCredentials = false;
smtpClient.Timeout = 100000;
smtpClient.Credentials = new System.Net.NetworkCredential(mailerEmailAddress, mailerPassword);
smtpClient.EnableSsl = EnableSsl;
All function must be surround by a try catch;
Try by removing
smtpClient.EnableSsl = true;
I am not sure whether vsnl supports SSL and the port number you are using
Without seeing your code, it is difficult to find the reason for exception. Following are assumptions:
The serverHost of VSNL is smtp.vsnl.net
Exception:
Unable to read data from the transport connection: net_io_connectionclosed
Usually this exception occurs only when there is mismatch in username or password.
Check to see if the machine is being referred to by an IPv6 address. In my case using machine name gave me the same error. Using the ip4 address it did work (i.e. 10.0.0.4). I got rid of ipv6 and it started to work.
Not the solution i was looking for but given my limited understanding of ipv6 I did not know of other choices.

Categories

Resources