SMTP header injection in ASP.NET? - asp.net

My ASP.NET website has a global error handler that sends an email to me (and another developer) when there is any kind of error in the web app. We recently received an error which contained a CC to an email address that we'd never heard of. The scary thing is that the list of developers that the error email is sent to is hard coded in compiled ASP.NET code. We don't see how the CC could have been added.
We're also very suspicious of foul play because the request that caused the error was an attempt to use one of our forms to send spam. The IP address that sent the request is also listed on http://www.projecthoneypot.org/.
Our best guess right now is that the request was malformed in some way that it injected a CC header into the email. The problem is that we can't figure out how this could be done. We're using System.Net.Mail to send the emails and it seems to protect against this sort of thing. The subject of the MailMessage object only accepts a single line so that you don't create a multiline subject with a CC line. Setting the to and cc addresses in the MailMessage seems pretty robust. And I can't see how you could add a CC header in the body of the message. I can't find any information on this and I'd love to know if this is a real problem.
EDIT: Someone requested the code. It's a little long, but here it is:
public class Global : System.Web.HttpApplication
{
protected void Application_Error(Object sender, EventArgs e)
{
// Get the last exception.
Exception objException = Server.GetLastError();
// Work out the error details based on the exception.
string ErrorType = "";
string ErrorDescription = "";
string ErrorHtml = "";
if (objException == null)
{
// This should never occur.
ErrorType = "Unknown Error";
ErrorDescription = "Unknown Error";
}
else if (objException.GetType() == typeof(HttpException))
{
// This will occur when the ASP.NET engine throws a HttpException.
HttpException objHttpException = objException as HttpException;
if (objHttpException.GetHttpCode() == 404)
{
string Resource = Globals.GetFullUrl(this.Context);
Server.ClearError();
Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
return;
}
else
{
ErrorType = objHttpException.GetHttpCode().ToString();
ErrorDescription = objHttpException.Message;
}
}
else if (objException.GetType() == typeof(HttpUnhandledException) && objException.InnerException != null && objException.InnerException.GetType() == typeof(HttpException))
{
// This will occur when the code throws a HttpException (e.g. a fake 404).
HttpException objHttpException = objException.InnerException as HttpException;
if (objHttpException.GetHttpCode() == 404)
{
string Resource = Globals.GetFullUrl(this.Context);
Server.ClearError();
Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
return;
}
else
{
ErrorType = objHttpException.GetHttpCode().ToString();
ErrorDescription = objHttpException.Message;
}
}
else if (objException.GetType() == typeof(HttpUnhandledException))
{
// This will occur when a page throws an error.
HttpUnhandledException objHttpUnhandledException = (HttpUnhandledException) objException;
ErrorType = objHttpUnhandledException.GetHttpCode().ToString();
if (objHttpUnhandledException.InnerException != null)
ErrorDescription = objHttpUnhandledException.InnerException.Message;
else
ErrorDescription = objHttpUnhandledException.Message;
if (objHttpUnhandledException.GetHtmlErrorMessage() != null)
{
ErrorHtml = objHttpUnhandledException.GetHtmlErrorMessage();
}
}
else if (objException.GetType() == typeof(HttpRequestValidationException) && !Globals.IsTtiUser(this.Context))
{
// Do nothing. This is mostly just spider junk and we don't want to know about it.
}
else
{
// This will occur when the ASP.NET engine throws any error other than a HttpException.
ErrorType = objException.GetType().Name;
ErrorDescription = objException.Message;
}
// Send an email if there's an error to report.
if (ErrorType != "" || ErrorDescription != "")
{
Globals.SendErrorEmail(this.Context, ErrorType, ErrorDescription, ErrorHtml);
}
}
public static void SendErrorEmail (HttpContext context, string errorType, string errorDescription, string errorHtml)
{
// Build the email subject.
string Subject = "EM: " + errorType + ": " + context.Request.ServerVariables["SCRIPT_NAME"];
// Build the email body.
string Body;
StringBuilder sb = new StringBuilder("");
sb.Append("Server:\r\n");
sb.Append(Globals.Server.ToString() + "\r\n");
sb.Append("\r\n");
sb.Append("URL:\r\n");
sb.Append(Globals.GetFullUrl(context) + "\r\n");
sb.Append("\r\n");
sb.Append("Error Type" + ":\r\n");
sb.Append(errorType + "\r\n");
sb.Append("\r\n");
sb.Append("Error Description" + ":\r\n");
sb.Append(errorDescription + "\r\n");
sb.Append("\r\n");
sb.Append("Referring Page:\r\n");
sb.Append(context.Request.ServerVariables["HTTP_REFERER"] + "\r\n");
sb.Append("\r\n");
sb.Append("Date/Time:\r\n");
sb.Append(DateTime.Now.ToString() + "\r\n");
sb.Append("\r\n");
sb.Append("Remote IP:\r\n");
sb.Append(context.Request.ServerVariables["REMOTE_ADDR"] + "\r\n");
sb.Append("\r\n");
sb.Append("User Agent:\r\n");
sb.Append(context.Request.ServerVariables["HTTP_USER_AGENT"] + "\r\n");
sb.Append("\r\n");
sb.Append("Crawler:\r\n");
sb.Append(context.Request.Browser.Crawler.ToString() + "\r\n");
sb.Append("\r\n");
sb.Append("Admin User:\r\n");
sb.Append(context.User.Identity.Name + "\r\n");
sb.Append("\r\n");
sb.Append("\r\n");
Body = sb.ToString();
// If there's HTML to represent the error (usually from HttpUnhandledException),
// then stuff the body text into the HTML (if possible).
bool HtmlMessage = false;
if (errorHtml != "")
{
Regex r = new Regex("(?<thebodytext><body.*?>)", RegexOptions.IgnoreCase);
if (r.IsMatch(errorHtml))
{
Body = Body.Replace("\r\n", "<br>");
Body = r.Replace(errorHtml, "${thebodytext}" + Body, 1);
HtmlMessage = true;
}
}
// Send an email to the TTI developers.
MailMessage objMail;
objMail = new MailMessage();
objMail.From = new MailAddress("from-address");
objMail.To.Add(new MailAddress("to-address"));
objMail.CC.Add(new MailAddress("cc-address"));
objMail.CC.Add(new MailAddress("another-cc-address"));
if (HtmlMessage)
objMail.IsBodyHtml = true;
else
objMail.IsBodyHtml = false;
if (errorType == "404")
objMail.Priority = MailPriority.Low;
else
objMail.Priority = MailPriority.High;
objMail.Subject = Subject;
objMail.Body = Body;
try
{
SmtpClient objSmtpClient = new SmtpClient();
objSmtpClient.Send(objMail);
}
finally
{
// Do nothing.
}
}
}

I could see this being the target of a VERY creative attack.... You are stuffing user controlled data into your message body... At which point, crafty use of binary data COULD result in a BODY that sends the proper data during the SMTP session to get it formatted JUST RIGHT... If I may, I'd suggest either converting the body to all ASCII text, or during your string building, write a string sanitizer that only allows RFC chars in. (Filters the URL's, the REFERRER, Remote Address, and UserAgent). Those are your more likely points of attack.
A second thought might be to construct a basic email in code, and ATTACH the body that you have constructed as a text, or HTML, or PDF file.
Keep in mind, SMTP ENVELOPE data is NOT the same as message data.... If someone was crafty enough to send the correct body that caused a CRLFCRLF.CRLFCRLF to be sent during the body part, that would terminate the sending, and then if they kept sending data, they could send the whole MAIL FROM: RCPT TO:, DATA, etc... (Granted, this is an unlikely scenario...)...
I'd LOVE to see the RAW source of the email you got... (As in the hex dump of the actual SMTP transaction, not what Outlook wants you to see, or whatever).
You may also try encoding your body using QP, or B64 before sending the message.... That might solve your problem...
This is an interesting one, and I'm looking forward to the outcome of it.

Your code looks very secure, so I don't think the problem is on your side.
IMO, either someone intercepted the SMTP message while it was being sent to the mailserver and injected the extra CC: line; or the mailserver has been compromised.
If you can't find an answer I suggest contacting Microsoft directly - you may have uncovered an exploit in the .NET Framework.

As a workaround, why don't you encript the email message using asymeterical encription (for example public key encription)? That way only the intended recepient will be able to read it.
In this way even if the bad guys get a copy of your message (by whatever means) it will be of now use to them.
Lets face it, if you have a high profile website like the FBI or Google, lots of very creative people will spend lots of time and go to great lengths to comprimise it. It is extremely important to protect detailed error messages.

Related

System.Net.WebClient The underlying connection was closed

The underlying connection was closed: The connection was closed unexpectedly
I'm receiving the error message when using WebClient. I had tested this with asp code and it is running pretty well. But when I try to run the exe version of the code it running the following error, and I able to access the request address from the server, and it is within the internal network.
My server setup :-
Windows Server 2003 Entrerprise SP2
asp.net 2.0.50727
iis v6.0
Here is some code:
Manually accessing the
protected static String cross_server_req(String strContent, String strPage, String strPrivateKey)
{
try
{
WebClient wc = new WebClient();
String strURL = SERVICE_PATH + strPage + "?r=" + DES_.DESEncrypt(strContent);
byte[] responseArray = wc.DownloadData(strURL);
String strResData = Encoding.UTF8.GetString(responseArray);
if (Config.RecordWebService == "1")
{
String strLogContent = "Request:" + strContent + "\r\nResponse:" + strResData + "\r\nDateCreated:" + D_Time.DNow + "\r\n\r\n";
ServiceLog.Logger(strPage, strLogContent);
}
if (null != strResData && String.Empty != strResData)
{
return strResData.Trim();
}
}
catch (Exception ex)
{
ServiceLog.Logger("cross_server_req() Exception:" + ex.Message + "\r\n" + ex.StackTrace);
}
return null;
}
Here is from log
cross_server_req() Exception:The underlying connection was closed: The connection was closed unexpectedly.
at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
at System.Net.WebClient.DownloadData(Uri address)
at System.Net.WebClient.DownloadData(String address)
at Account.cross_server_request_curl(String strContent, String strPage, String strPrivateKey)
Please let me know any suggestion help this problem? I had look around the site and no solution had found.
I believe this error may have something to do with TLS/SSL connectivity assuming your hitting a HTTPS url. Have a look at this thread. Essentially you need to provide some code to verify that the certificate is valid. This is needed for CA's that have thumbprint issues or that aren't fully trusted. Hopefully this helps to solve your issue.
System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(validateSSLCert);
private static bool validateSSLCert(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}

Understanding how SmtpClient handles retries

I'm working against a GoogleApps account for sending event notifications from my (mvc) web-app. Usually everything works fine. When the system is asked to send more than 75 messages or so I'm seeing replies from the SMTP server:
Service not available, closing
transmission channel. The server
response was: 4.7.0 Try again later,
closing connection. (MAIL)
uf10sm1153163icb.17
However, the system is auto-retrying and anything my system is asked to send eventually (by everything i can tell as this point) making it out. But given how the code generates and sends the emails I don't understand how these re-tries are handled.
I'd like to try to slow down the transmission in hopes that whatever's causing the 'Service Not Available' condition will be placated if the submissions occur asynchronously. But from the looks of the code, it already is since i'm using a Try | catch block.
Here's the relevant bit of my facade code:
foreach (string email in recipientEmails)
{
try
{
EmailGateway.Instance.SendEmail(email, notificationSubject, notificationMessage);
}
catch (Exception ex)
{
Logger.Instance.LogException(ex);
Logger.Instance.LogMessage("ERROR! Unsent email is to: " + email );
}
Logger.Instance.LogMessage("Sent " + notificationSubject + " to " + email);
}
And here's the Gateway code (using System.Net.Mail;):
public virtual void SendEmail(string replyToAddress, string toEmailAddress, string subject, string body)
{
string destinationEmailAddress = toEmailAddress;
string fromEmailAddress = "my#address.com";
bool useSSL = "true";
MailMessage message = new MailMessage(fromEmailAddress, destinationEmailAddress, subject, body);
message.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.EnableSsl = useSSL;
smtp.Send(message);
}
So i'm catching both successes and fails into my logger table. What I don't understand is how I can see a log message for both a fail and then a success condition for the same email address. That indicates a 'retry' and, while i'm not surprised that the SmtpClient (the native .net assembly) can retry without explicit code asking it to, I don't see how my facade's code is being made to log both conditions.
SmtpClient is not retrying to send the email.
In your facade code as it is, you are always logging a success, whether you are getting an exception or not.
You should log success in the try block, otherwise you are catching the exception (logging failure), coming out of the catch block and logging success anyway, which is what you are observing.
foreach (string email in recipientEmails)
{
try
{
EmailGateway.Instance.SendEmail(email, notificationSubject, notificationMessage);
Logger.Instance.LogMessage("Sent " + notificationSubject + " to " + email);
}
catch (Exception ex)
{
Logger.Instance.LogException(ex);
Logger.Instance.LogMessage("ERROR! Unsent email is to: " + email );
}
}

Why am I getting "(304) Not Modified" error on some links when using HttpWebRequest?

Any ideas why on some links that I try to access using HttpWebRequest I am getting "The remote server returned an error: (304) Not Modified." in the code?
The code I'm using is from Jeff's post here (the page seems to have disappeared, see an archive copy at the Wayback Machine).
Note the concept of the code is a simple proxy server, so I'm pointing my browser at this locally running piece of code, which gets my browsers request, and then proxies it on by creating a new HttpWebRequest, as you'll see in the code. It works great for most sites/links, but for some this error comes up. You will see one key bit in the code is where it seems to copy the http header settings from the browser request to it's request out to the site, and it copies in the header attributes. Not sure if the issue is something to do with how it mimics this aspect of the request and then what happens as the result comes back?
case "If-Modified-Since":
request.IfModifiedSince = DateTime.Parse(listenerContext.Request.Headers[key]);
break;
I get the issue for example from http://en.wikipedia.org/wiki/Main_Page
PS. UPDATE HERE
Still can't work this out. Basically I can identify 1 link which has an issue, and it seems to work fine, 2nd time it gets the error, 3rd time OK, 4th time gets the error, 5th time OK etc. As if there is some state not getting cleared or something in the code. I've tried to clean up the code a bit using "using" type statements etc.
Here's the code. If anyone can spot why every 2nd time I browse to a link like http://newsimg.bbc.co.uk/css/screen/1_0_16/nol/v4/story.css (starting at the 2nd time, not the first) via this proxy code I get the error I'd love to hear.
class Program
{
static void Main(string[] args)
{
Proxy p = new Proxy(8080);
Thread proxythread = new Thread(new ThreadStart(p.Start));
proxythread.Start();
Console.WriteLine("Proxy Started. Press Any Key To Stop...");
Console.ReadKey();
p.Stop();
}
}
public class Proxy
{
private HttpListener _listener;
private int _port;
public Proxy(int port)
{
int defaultport = 8080;
// Setup Thread Pool
System.Threading.ThreadPool.SetMaxThreads(50, 1000);
System.Threading.ThreadPool.SetMinThreads(50, 50);
// Sanitize Port Number
if (port < 1024 || port > 65535)
port = defaultport;
// Create HttpListener Prefix
string prefix = string.Format("http://*:{0}/", port);
_port = port;
// Create HttpListener
_listener = new HttpListener();
_listener.Prefixes.Add(prefix);
}
public void Start()
{
_listener.Start();
while (true)
{
HttpListenerContext request = null;
try
{
request = _listener.GetContext();
// Statistics (by Greg)
int availThreads = -1;
int compPortThreads = -1;
ThreadPool.GetAvailableThreads(out availThreads, out compPortThreads);
log("INFO", request.Request.Url.ToString(), "START - [" + availThreads + "]");
ThreadPool.QueueUserWorkItem(ProcessRequest, request);
}
catch (HttpListenerException ex)
{
log("ERROR", "NA", "INFO: HttpListenerException - " + ex.Message);
break;
}
catch (InvalidOperationException ex)
{
log("ERROR", "NA", "INFO: InvalidOperationException - " + ex.Message);
break;
}
}
}
public void Stop()
{
_listener.Stop();
}
private void log(string sev, string uri, string message)
{
Console.Out.WriteLine(Process.GetCurrentProcess().Id + " - " + sev + " (" + uri + "): " + message);
}
private void ProcessRequest(object _listenerContext)
{
#region local variables
HttpWebRequest psRequest; // Request to send to remote web server
HttpWebResponse psResponse; // Response from remote web server
List<byte> requestBody = new List<byte>(); // Byte array to hold the request's body
List<byte> responseBody = new List<byte>(); // Byte array to hold the response's body
byte[] buffer;
string uri = "";
#endregion
var listenerContext = (HttpListenerContext)_listenerContext;
uri = listenerContext.Request.Url.ToString().Replace(string.Format(":{0}", _port), "");
// Create Interent Request
HttpWebRequest internetRequest = (HttpWebRequest)WebRequest.Create(uri);
#region Build Request Up
internetRequest.Method = listenerContext.Request.HttpMethod;
internetRequest.ProtocolVersion = listenerContext.Request.ProtocolVersion;
internetRequest.UserAgent = listenerContext.Request.UserAgent;
foreach (string key in listenerContext.Request.Headers.AllKeys)
{
try
{
switch (key)
{
case "Proxy-Connection":
case "Connection":
internetRequest.KeepAlive = (listenerContext.Request.Headers[key].ToLower() == "keep-alive") ? true : false;
break;
case "Content-Length":
internetRequest.ContentLength = listenerContext.Request.ContentLength64;
break;
case "Content-Type":
internetRequest.ContentType = listenerContext.Request.ContentType;
break;
case "Accept":
internetRequest.Accept = listenerContext.Request.Headers[key];
break;
case "Host":
break;
case "Referer":
internetRequest.Referer = listenerContext.Request.Headers[key];
break;
case "If-Modified-Since":
internetRequest.IfModifiedSince = DateTime.Parse(listenerContext.Request.Headers[key]);
break;
default:
internetRequest.Headers.Add(key, listenerContext.Request.Headers[key]);
break;
}
}
catch (Exception ex)
{
Console.WriteLine("Error settup up psRequest object. Error = " + ex.Message + "\n" + ex.StackTrace);
}
}
#endregion
#region Copy content into request
buffer = new byte[1024];
using (Stream instream = listenerContext.Request.InputStream)
{
int incount = instream.Read(buffer, 0, buffer.Length);
while (incount > 0)
{
internetRequest.GetRequestStream().Write(buffer, 0, incount);
incount = instream.Read(buffer, 0, buffer.Length);
}
}
#endregion
// Get Internet Response
HttpWebResponse internetResponse = null;
try
{
using (internetResponse = (HttpWebResponse)internetRequest.GetResponse())
{
#region Configure Local Response Header Keys
foreach (string key in internetResponse.Headers.Keys)
{
try
{
switch (key)
{
case "Transfer-Encoding":
listenerContext.Response.SendChunked = (internetResponse.Headers[key].ToLower() == "chunked") ? true : false;
break;
case "Content-Length":
listenerContext.Response.ContentLength64 = internetResponse.ContentLength;
break;
case "Content-Type":
listenerContext.Response.ContentType = internetResponse.Headers[key];
break;
case "Keep-Alive":
listenerContext.Response.KeepAlive = true;
break;
default:
listenerContext.Response.Headers.Add(key, internetResponse.Headers[key]);
break;
}
}
catch (Exception ex)
{
log("ERROR", uri, "Error settup up listenerContext.Response objects. Error = " + ex.Message + "\n" + ex.StackTrace);
}
}
#endregion
try
{
// Transfer the body data from Internet Response to Internal Response
buffer = new byte[1024];
using (Stream inputStream = internetResponse.GetResponseStream())
{
int outcount = inputStream.Read(buffer, 0, buffer.Length);
while (outcount > 0)
{
listenerContext.Response.OutputStream.Write(buffer, 0, outcount);
outcount = inputStream.Read(buffer, 0, buffer.Length);
}
}
}
catch (Exception ex)
{
log("ERROR", uri, "Could not obtain response from URI: " + ex.Message);
}
finally
{
listenerContext.Response.OutputStream.Close();
}
}
}
catch (Exception ex)
{
//if (ex is InvalidOperationException ||
// ex is ProtocolViolationException ||
// ex is WebException)
//{
// log(uri, "Could not successfully get response: " + ex.GetType() + " - " + ex.Message);
// listenerContext.Response.Close();
// return;
//}
//else { throw; }
log("ERROR", uri, "Could not successfully get response: " + ex.GetType() + " - " + ex.Message);
listenerContext.Response.Close();
}
}
}
And here is an example of what I see - first hit is good, 2nd has error...
Proxy Started. Press Any Key To Stop...
2080 - INFO (http://newsimg.bbc.co.uk:8080/css/screen/1_0_16/nol/v4/story.css): START - [50]
2080 - INFO (http://newsimg.bbc.co.uk:8080/css/screen/1_0_16/nol/v4/story.css): START - [50]
2080 - ERROR (http://newsimg.bbc.co.uk/css/screen/1_0_16/nol/v4/story.css): Could not successfully get response: System.Net.WebException - The remote server returned an error: (304) Not Modified.
First, this is not an error. The 3xx denotes a redirection. The real errors are 4xx (client error) and 5xx (server error).
If a client gets a 304 Not Modified, then it's the client's responsibility to display the resouce in question from its own cache. In general, the proxy shouldn't worry about this. It's just the messenger.
This is intended behavior.
When you make an HTTP request, the server normally returns code 200 OK. If you set If-Modified-Since, the server may return 304 Not modified (and the response will not have the content). This is supposed to be your cue that the page has not been modified.
The authors of the class have foolishly decided that 304 should be treated as an error and throw an exception. Now you have to clean up after them by catching the exception every time you try to use If-Modified-Since.
Just pressing F5 is not always working.
why?
Because your ISP is also caching web data for you.
Solution: Force Refresh.
Force refresh your browser by pressing CTRL + F5 in Firefox or Chrome to clear ISP cache too, instead of just pressing F5
You then can see 200 response instead of 304 in the browser F12 developer tools network tab.
Another trick is to add question mark ? at the end of the URL string of the requested page:
http://localhost:52199/Customers/Create?
The question mark will ensure that the browser refresh the request without caching any previous requests.
Additionally in Visual Studio you can set the default browser to Chrome in Incognito mode to avoid cache issues while developing, by adding Chrome in Incognito mode as default browser, see the steps (self illustrated):
It is not an issue it is because of caching...
To overcome this add a timestamp to your endpoint call, e.g. axios.get('/api/products').
After timestamp it should be axios.get(/api/products?${Date.now()}.
It will resolve your 304 status code.
I think you have not installed these features. see below in picture.
I also suffered from this problem some days ago. After installing this feature then I solved it. If you have not installed this feature then installed it.
Install Process:
go to android studio
Tools
Android
SDK Manager
Appearance & Behavior
Android SDK

Not all e-mails being sent using SmtpClient in an ASP.NET MVC getting delivered. Why? How to resolve?

Here is the set-up:
I have a Notifications controller that is called from task scheduler 1x/day
The action method pulls upwards of 300 addresses, loops thru them and uses the SmtpClient class to send an individual e-mail to each recepient.
From what I can tell the process runs fine with no exceptions ... except that not all e-mails are being delivered. Anyone have any ideas on what is going on and how to resolve?
Here is the code:
foreach (var emp in division.Users)
{
var fromAddress = "myfromaddress";
var mailServer = "mymailserver";
var toEmail = emp.EmailAddress;
var message = new MailMessage(fromAddress, toEmail)
{
Subject = subject,
Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>",
IsBodyHtml = true
};
var client = new SmtpClient(mailServer);
client.Send(message);
}
UPDATE:
Adding a pause in between sending e-mails resolves the problem. But why does this work? And is there a better way (e.g. using Async()) that would equally resolve the issue in a better way???
Updated code ...
foreach (var emp in division.Users)
{
var fromAddress = "myfromaddress";
var mailServer = "mymailserver";
var toEmail = emp.EmailAddress;
var message = new MailMessage(fromAddress, toEmail)
{
Subject = subject,
Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>",
IsBodyHtml = true
};
var client = new SmtpClient(mailServer);
client.Send(message);
Thread.Sleep(3000); // Wait 3s until sending next message
}
there is a default timeout with the smtp client and default value is 100sec
more info here
If you are not having any exceptions I'd check SPAM folders and email addresses. I'd also try sending an email manually from your outlook to one of the addresses that didn't recieve a message.
On a side note, unless you are using different mail servers, I think you can change this code to
var client = new SmtpClient(mailServer);
var mailServer = "mymailserver";
foreach (var emp in division.Users)
{
var fromAddress = "myfromaddress";
var toEmail = emp.EmailAddress;
var message = new MailMessage(fromAddress, toEmail)
{
Subject = subject,
Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>",
IsBodyHtml = true
};
client.Send(message);
}
You might also try SendAsync method of the SmtpClient class, like this:
// setup the callback method when the send finishes
client.SendCompleted += SendComplete; //new SendCompletedEventHandler(smtpSender_SendCompleted);
// send the email
client.SendAsync(message, null);
private void SendComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
// do stuff on complete
}
I would strongly advice on using SmtpClient.SendAsync() as Send() is blocking.
I would check the logs of the SMTP server that you're sending to. Note: sending your own emails are more likely to end in Junk mail than using a trusted provider.
Edit: added sample SendAsync code
smtpClient.SendCompleted += smtpClient_SendCompleted;
static void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
Log.ErrorFormat("Async Mail exception {0} :: {1}",
e.Error.GetType().Name, e.Error.Message);
}
}

Actionscript 2.0 Email form LoadVars with ashx .net handler

I have a flash as 2.0 file that i need to send emails via an asp handler. First off, is this possible? Second, if it is, how do i get the return to have a status=true?
the .net codebehind
public void ProcessRequest(HttpContext context)
{
//E-Mail Method
string response = "sent=success";
MailAddress fromAddress = new MailAddress(context.Request.QueryString["Email"].ToString(), context.Request.QueryString["Name"].ToString());
MailAddress toAddress = new MailAddress("emailInbox#site.com", "Goons");
MailMessage message = new MailMessage(fromAddress, toAddress);
message.Subject = context.Request.QueryString["Name"].ToString() + " sent you a message from the website.";
message.Body = context.Request.QueryString["Msg"].ToString();
SmtpClient client = new SmtpClient("mail.grassrootsdm.com");
// Include credentials if the server requires them.
NetworkCredential SMTPUserInfo = new NetworkCredential("mailsenderemail","password");
client.Credentials = SMTPUserInfo;
try {
client.Send(message);
}
catch (Exception ex) {
response = ex.ToString();
}
context.Response.Write(response);
}
the actionscript
if (i == 0) {
sendVars.Name = fieldName.field.text;
sendVars.Email = fieldEmail.field.text;
sendVars.Msg = fieldMsg.field.text;
sendVars.sendAndLoad("http://www.grassrootsdm.com/WebService/EmailHandler.ashx", statusVars, "POST");
statusMsg.text = "Sending...";
statusVars.onLoad = function(success:Boolean) {
if (success) {
if (statusVars.sent == "success") {
clearForm();
statusMsg.text = "Message sent";
}
} else {
statusMsg.text = "Error!";
}
clearInterval(clearStatus);
clearStatus = setInterval(clearStatusInt, 3000);
};
}
Yes, it is possible.
Read the important notes at the bottom of each codes pertain to sending and retrieving data from flash to .net page. Explanation of the code is in the comment inside the code.
Flash Part (Action Script 2)
//function to send invoke .net page to send email
//use other control/button to call this function
//important: in order for the 'onLoad' event to work correctly, this function has to be 'Void'
function sendMail():Void
{
//show status
statusMsg.text = "Sending...";
//create LoadVars object
var lv_in:LoadVars = new LoadVars();
var lv_out:LoadVars = new LoadVars();
//set onLoad event
lv_in.onLoad = function(success:Boolean)
{
//if success, meaning data has received from .net page, run this code
if (success)
{
//lv_in.sent is used to parsed out message/data from .Net page
statusMsg.text = "Message sent!" + lv_in.sent;
}
//if fail, run this code
else
{
statusMsg.text = "Error!";
}
}
//begin invoke .net page to send email
lv_out.sendAndLoad("SendMail.aspx", lv_in, "POST");
}
Important note:
The function that contain onLoad event, in this case sendMail function, has to be Void function, meaning it's not returning value. If this function return value, what happen is the function will be executed all the way without waiting for the data for the return data from .net page, thus the onLoad event will not be set properly.
.Net Part
I copied the OP's .Net code so assuming this code works when sending email.
public void ProcessRequest(HttpContext context)
{
//E-Mail Method
string response = "sent=Success&";
MailAddress fromAddress = new MailAddress(context.Request.QueryString["Email"].ToString(), context.Request.QueryString["Name"].ToString());
MailAddress toAddress = new MailAddress("emailInbox#site.com", "Goons");
MailMessage message = new MailMessage(fromAddress, toAddress);
message.Subject = context.Request.QueryString["Name"].ToString() + " sent you a message from the website.";
message.Body = context.Request.QueryString["Msg"].ToString();
SmtpClient client = new SmtpClient("mail.grassrootsdm.com");
// Include credentials if the server requires them.
NetworkCredential SMTPUserInfo = new NetworkCredential("mailsenderemail","password");
client.Credentials = SMTPUserInfo;
try
{
client.Send(message);
}
catch (Exception ex)
{
response = ex.ToString();
}
context.Response.Write(response);
}
Important note:
The only thing I changed from the OP's .Net code is the response message. It was originally "sent=success" which I changed to "sent=success&".
The reason for this is, if you want action script to parse the posted message/data from .Net, it will stop at & symbol, thus leave the rest of the message alone and only get the message under sent variable.

Resources