We have two versions of a web application running in IIS 7.5 on Windows Server 2008R2, with almost identical running conditions. Both versions are using the same set of email code to relay smtp messages to an internal Exchange2010 server. The first application completes the request, and sends the email without a hitch. However, the second, which uses a custom security model (being the only major difference between the apps), will not even initiate an smtp request at all. There is code to handle exceptions from SMTPClient.send, but none are occurring. Both versions send mail from development machine running with visual studio application server.
Wireshark shows complete request and verification of credentials for application one, but no traffic is detected at all from application two. The virtual running the IIS instance has it's IP address accepted by the Exchange server, and is on the same domain etc. The firewall is turned off for the domain.
UseDefaultCredentials is being implemented for authentication of smtp messages. Each application is running inside a separate app pool, but are using the same user (NetworkService) and have identical security permissions on the wwwroot etc.
Any insight is appreciated as to why the one application is seemingly doing nothing when using .Net Mail.SMTPClient on the IIS 7.5 server.
Code in a nutshell is as follows (ignore possible method signature mismatches, code is in different classes, default SMTP host is defined by Email.Host)
protected void taskHeaderGrid_OnItemCommand(object sender, GridCommandEventArgs e)
{
try {
Int32 recordsAcivated = workFlowController.activateWorkFlow((IDbConnection)myConn, null, System.Convert.ToInt32(taskHdrIdTxt));
}
catch (Exception) {
AddMessage(Message.eMessageType.Error, "Warning: email message to alert users that next task has been activated was not sent.");
}
}
public Int32 activateWorkFlow(IDbConnection currConnection, IDbTransaction currTran, Int32 workFlowId)
{
//Send out the mails......
if (!string.IsNullOrWhiteSpace(primaryPersonEmail))
{
emailController.sendMessage(primaryPersonEmail, "Task has been activated.", string.Format("Hdr:({0}) Detail:({1})", taskHeaderDTO.Description, jobFunctionDTO.JobDescription));
}
if (!string.IsNullOrWhiteSpace(secondaryPersonEmail))
{
emailController.sendMessage(secondaryPersonEmail, "Task has been activated.", string.Format("Hdr:({0}) Detail:({1})", taskHeaderDTO.Description, jobFunctionDTO.JobDescription));
}
}
public void sendMessage(string toEmailAddr, string txtmessage, string subject)
{
Email.Host = hostName;
Email.Send(subject, txtmessage, senderEmailAddr, toEmailAddr);
}
public static void Send(string subject, string body, string from, IEnumerable<string> to, string smtphost)
{
Send(CreateMessage(subject, body, from, to), smtphost);
}
public static void Send(System.Net.Mail.MailMessage msg, string smtphost)
{
using (System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient(smtphost))
{
if (InterceptEmails == true)
{
ApplyFailSafe(msg);
}
client.UseDefaultCredentials = true;
client.Send(msg);
}
}
public static System.Net.Mail.MailMessage CreateMessage(string subject, string body, string from, IEnumerable<string> to, IEnumerable<string> cc, IEnumerable<string> bcc)
{
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
msg.Subject = subject;
msg.Body = body;
msg.From = new System.Net.Mail.MailAddress(from);
msg.IsBodyHtml = true;
if (to != null)
{
foreach (string email in to)
msg.To.Add(email);
}
if (cc != null)
{
foreach (string email in cc)
msg.CC.Add(email);
}
if (bcc != null)
{
foreach (string email in bcc)
msg.Bcc.Add(email);
}
return msg;
}
I've created an example method for you, that will attempt to send an e-mail. Here are a couple of items to note about the implementation:
Settings Class - It holds all of our Client / Server data. Which helps keep the code decoupled for re-usability.
public static void SendNotificationEmail(Settings setting)
{
// Loop through our generic list.
foreach(string email in setting.To)
{
// Assign our email parameters to the message.
MailMessage message = new MailMessage(setting.From, email, setting.Subject, setting.Body);
//Build Our Smtp Client
SmtpClient client = new SmtpClient();
client.Host = setting.SmtpServer;
client.Port = setting.Port;
client.Timeout = setting.Timeout;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(setting.Username, setting.Password);
}
}
In order to truly help you we would need that Security Model and the precise code that is giving you trouble. Hopefully my implementation might contain a missing piece. This works on my server running the latest version of Internet Information System (IIS).
Also SMTP may fail silently without valid credentials.
Issue was resolved, a higher level configuration and error before the SMTP email was being generated caused the issue.
Related
I am having an issue with SmtpClient in an ASP.NET web application.
I have a generic function that builds an email message and then sends it. The code is as follows:
public static bool SendMessage( string fromName, string toName, string subject, string body ) {
var smtpClient = new SmtpClient("server address here")
{
Port = 587,
Credentials = new NetworkCredential("user", "pass"),
EnableSsl = false,
};
var mailMessage = new MailMessage
{
From = new MailAddress("sender", "Testing"),
Subject = subject,
Body = body
};
mailMessage.To.Add ( new MailAddress(toName, "Valued Customer") );
try {
smtpClient.Send ( mailMessage );
return true;
}
catch (Exception ex) {
var error = $"ERROR :{ex.Message}";
return false;
}
}
The problem is, I get the following error when I call it:
Mailbox unavailable. The server response was: <email address being sent to> No such user here
Naturally I removed the value in the < >, but in the original error message it is the email address of the recipient. I almost think the SMTP server believes the recipient has to be a user on the system.
What can I try next? I even hard-coded email addresses in rather than using variables, thinking maybe there was some weird issue with that, but it didn't work.
The error is telling you that the the SMTP server does not have a user with that email address (usually it has to do with security around the FROM address). The SMTP server will not send email if it does not recognize the FROM address.
Solution, change your FROM. Example:
var mailMessage = new MailMessage
{
From = new MailAddress("tester", "test#adminsystem.com"),
Subject = subject,
Body = body
};
I'm experiencing a weird problem, as the title says whenever I try to send a mail, the following exception is thrown:
System.Net.Mail.SmtpException: 'The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at'
Nothing out of the ordinary, however this is a code that was written about 2 years ago and hasn't been touched since, today when I ran it - suddenly doesn't work.
public static Task SendEmailAsync(string email, string subject, string htmlMessage)
{
return Task.Run(() =>
{
using (var client = BuildClient())
{
var message = BuildMessage(email, subject, htmlMessage);
client.Send(message);
}
});
}
private static SmtpClient BuildClient()
{
var smtp = new SmtpClient("smtp.gmail.com", 587)
{
EnableSsl = true,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("xxxxx#abv.bg", "xxx")
};
return smtp;
}
private static MailMessage BuildMessage(string email, string subject, string htmlMessage)
{
var mailMessage = new MailMessage
{
From = new MailAddress("xxxx#abv.com"),
Subject = subject,
Body = htmlMessage
};
mailMessage.To.Add(email);
return mailMessage;
}
As you can see the host is gmail.com, but I'm using a different email provider abv.bg, I've also tried swapping that with a gmail account, but the error is still the same.
This is a somewhat shortened version of the original code, but this also produces the error, since im not using gmail, there is no such a thing as "Less secure apps", or 2fa, this cant be the cause and even if it was when I attempted to use a gmail account, I enabled the less secure apps option, to no avail. I've ran this code under both .net core 3.0 and .net framework 4.7.2, same results. I'm also running this completely locally, so time zones shouldn't be a problem. And I've tripled, quadrupled checked the password and email.
So I'm basically clueless to why this is happening, any tips would be appreciated.
We use the excellent AuthSMTP service for outgoing mail from our MVC application. Until we upgraded to .Net 4.5.1 we used SmtpMail.SendAsync to send out multiple emails at once via IIS7. IIS7 is set to relay mail through AuthSMTP.
These days asynchronous code in .Net seems to work differently. We rolled back to SmtpMail.Send which has slowed the site down where multiple mails are sent. We are considering the following options.
Rewrite the code to work with the Task-based Asynchronous Pattern. We're fairly confused by this but could persevere if it's a good option.
Save email to the database and send it using a console application triggered as a scheduled task. We like this option because it gives us an archive of sent email. On the other hand we'd need to hit the database to store the emails, which may be slower than asking IIS to dump outgoing mail to a queue folder.
Have IIS save outgoing mail to a queue folder, and write a console application to process that queue. We could archive each message on disk, which is a worse archiving solution than storing in database.
Something else.
Can anyone tell us the most performant solution base on their experience?
Thanks!
Call your email function in a separate thread, that will send emails in background
Try this code.
public static void SendEmail(string from, string[] to, string[] CC, string[] BCC, string subject, string body, SMTPSettings _smtp = null)
{
Thread email = new Thread(delegate()
{
SendAsyncEmail(from, to, CC, BCC, subject, body, _smtp);
});
email.IsBackground = true;
email.Start();
}
private static void SendAsyncEmail(string from, string[] to, string[] CC, string[] BCC, string subject, string body, SMTPSettings _smtp = null)
{
try
{
MailMessage message = new MailMessage();
SmtpClient client = new SmtpClient();
if (_smtp != null)
{
client.Host = _smtp.SMTPServer;
client.Port = Convert.ToInt32(_smtp.SMTPPort);
client.EnableSsl = _smtp.SMTPEnableSSL;
client.Credentials = new System.Net.NetworkCredential(_smtp.SMTPUserEmail, SMTPPassword);
}
message.From = new MailAddress(from);
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = true;
foreach (string t in to)
{
message.To.Add(new MailAddress(t));
}
if (CC != null)
foreach (string c in CC)
{
message.CC.Add(new MailAddress(c));
}
if (BCC != null)
foreach (string b in BCC)
{
message.Bcc.Add(new MailAddress(b));
}
client.Send(message);
}
catch (Exception ex)
{
ErrorLogRepository.LogErrorToDatabase(ex, null, null, "");
}
}
I'm using the System.Net.Mail. There are some topics around this area, but they are ASP.NET and often VB related. I'm isolating the code into a desktop skeleton code, I use .NET 3.5 and C#.
So Send works in all scenario what I tried (EnableSsl false/true, UseDefaultCredentials false/true). But SendAsync only works if UseDefaultCredentials is not set to true (turns out that it can even matter if you explicitly set it to false, it's false by default), EnableSsl is true (OK, that can be server settings too), and hard-code my credentials. I want to be able to SendAsync using UseDefaultCredentials.
Code:
void sendmail() {
MailMessage email = new MailMessage();
email.From = new MailAddress("tcs#software.com");
email.To.Add("tcs#software.com");
email.Subject = "Simple test email subject";
email.Body = "Simple test email body";
string mHost = "mail.software.com";
string mUsername = #"DOMAIN\tcs";
string mPassword = "myfreakinpassword?Really???";
SmtpClient smtpCli = new SmtpClient(mHost);
//smtpCli.UseDefaultCredentials = true;
smtpCli.Credentials = new NetworkCredential(mUsername, mPassword);
smtpCli.EnableSsl = true;
smtpCli.SendCompleted += smtpCli_SendCompleted;
try {
//smtpCli.Send(email);
smtpCli.SendAsync(email, null); // This mofo only works in this combination
}
catch (Exception ex) {
Console.WriteLine(ex);
}
}
void smtpCli_SendCompleted(object sender, AsyncCompletedEventArgs e) {
if (e.Error != null)
Console.WriteLine(e.Error);
}
Use messaging pattern like Prism's EventAggregator (specifying ThreadOption.BackgroundThread). This way the caller sends a message (the message would contain From, To, Subject, Body), and it is asynchronous from the sender's point of view. Then use the synchronous Send function of System.Net.Mail in the consumer/handler of the message.
This probably works because the executing background thread has more proper privileges than the one spawns the SendAsync.
I've written several programs that send email from C#. This works great in winXP, but I find it breaks in Win7. My understanding is that even though the SMTP server I'm referencing is on another computer, the sending computer needs to have the SMTP service installed (and win7 does not).
I know its possible to install a third party SMTP server, but then I'd need to do that on every computer running my programs. Instead, I'd like to include a temporary SMTP server in my project that I can use entirely from code to do the same job. Does anyone know of a library (or sample code) on how I can include a temporary SMTP server in my project?
Here is my code:
public static void sendEmail(String[] recipients, String sender, String subject, String body, String[] attachments)
{
MailMessage message;
try
{
message = new MailMessage(sender, recipients[0]);
}
catch (Exception)
{
return;
}
foreach (String s in recipients)
{
if (!message.To.Contains(new MailAddress(s)))
message.To.Add(s);
}
message.From = new MailAddress(sender);
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient("PRIVATE.PRIVATE.PRIVATE", 25);
smtp.DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis;
//smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = true;
if (attachments.Length > 0)
{
foreach (String a in attachments)
{
message.Attachments.Add(new Attachment(a));
}
}
try
{
smtp.SendAsync(message, null);
To send emails from c#, you do not need a local SMTP service. You just need the System.Net.Mail library. Using a remote SMTP server (possibly one with valid PTR settings and not one in your network to avoid being regarded as a spammer) should definitely suffice.
It may be a credentials issue. Change SendAsync to Send to see if you are getting any exceptions. Or add a handler for the Async invocation
smtp.SendCompleted += delegate(object s, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
System.Diagnostics.Trace.TraceError(e.Error.ToString());
}
};
Following changes to your code works for me in Win7
SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587);
//smtp.DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.Credentials = new NetworkCredential(GoogleUserEmail, GooglePassword);
smtp.EnableSsl = true;
// smtp.UseDefaultCredentials = true;
if (attachments != null && attachments.Length > 0)
{
foreach (String a in attachments)
{
message.Attachments.Add(new Attachment(a));
}
}
try
{
smtp.Send(message);
}
I have never found an embeddable SMTP server, but both of these are close and you could probably modify them to fit your needs.
http://www.codeproject.com/KB/IP/smtppop3mailserver.aspx
http://www.ericdaugherty.com/dev/cses/developers.html
I'm going to keep looking because this is also something I'd find useful. I'll post more if I find any.
If you just use an unconfigured service to send your emails you will definitely end up in the SPAM folder due to reverse DNS and SPF checks failing. So you'll want to configure your server properly. Alternatively you can use a 3rd party service like Elastic Email. Here is Elastic Email's sample code which uses HTTP to send the mail:
public static string SendEmail(string to, string subject, string bodyText, string bodyHtml, string from, string fromName)
{
WebClient client = new WebClient();
NameValueCollection values = new NameValueCollection();
values.Add("username", USERNAME);
values.Add("api_key", API_KEY);
values.Add("from", from);
values.Add("from_name", fromName);
values.Add("subject", subject);
if (bodyHtml != null)
values.Add("body_html", bodyHtml);
if (bodyText != null)
values.Add("body_text", bodyText);
values.Add("to", to);
byte[] response = client.UploadValues("https://api.elasticemail.com/mailer/send", values);
return Encoding.UTF8.GetString(response);
}
Have you tried specifying SMTP settings in an App.config file? Something like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<specifiedPickupDirectory pickupDirectoryLocation="C:\tmp"/>
<network host="smtp.example.com"/>
</smtp>
</mailSettings>
</system.net>
</configuration>
If you change deliveryMethod="SpecifiedPickupDirectory" then it'll just write a file representing the email that would be sent to the directory you specify.