I have the following function which sends mail. The body of the mail has a link (href) in some cases.
public static void SendMail(string from, string to, string subject, string message, bool isHTML = true)
{
if (!String.IsNullOrEmpty(to) && ConfigurationManager.AppSettings["no_mail"] == null)
{
MailMessage mailMessage = new MailMessage(from,
to,
subject,
message);
string bccAddr = ConfigurationManager.AppSettings["managementMailAddress"];
if (!String.IsNullOrEmpty(bccAddr))
mailMessage.Bcc.Add(bccAddr);
bccAddr = ConfigurationManager.AppSettings["debugMailAddress"];
if (!String.IsNullOrEmpty(bccAddr))
mailMessage.Bcc.Add(bccAddr);
if (isHTML)
mailMessage.IsBodyHtml = true;
//mailMessage.BodyEncoding = System.Text.Encoding.UTF8; // avoid 3D?
SmtpClient smtpClient = new SmtpClient(ConfigurationManager.AppSettings["mailHost"]);
smtpClient.Send(mailMessage);
}
}
Yesterday the mail clients started receiving mails with 3D inserted after the equals sign, and so ceased to work properly.
For example, I see "...href=3Dhttp://..." instead of "...href=http://...".
I made a small change in the code with reference to the BCC list, but nothing that should have a serious effect. The web.config file has not changed, other than putting in various mail addresses in configuration variables.
Why are my links broken?
Related
I have a method, which saves screenshot by the definite path and then makes email message, attaching screenshot to it. As I've understood, after sending it - the special thread is being created in which attachment file is used, so I can't delete it while that thread is working. So, I need to know if when the file will be accessible for deleting.
Here's my code:
-- Configuring smtp
private SmtpClient CreateSMTP()
{
var smtp = new SmtpClient("gate");
smtp.UseDefaultCredentials = false;
smtp.Credentials = new NetworkCredential("notifications#****.com", "3eCMCQxFde");
smtp.Port = 25;
smtp.EnableSsl = false;
return smtp;
}
-- Making message
public MailMessage MakeMessage(bool screenshotFlag)
{
MailAddress from = new MailAddress("notifications#****.com", Name);
MailAddress to = new MailAddress("****#****.com");
MailMessage message = new MailMessage(from, to);
message.Subject = Subject == string.Empty ? string.Empty : Subject;
message.Body = MessageText;
message.Body = GenerateLogAndExceptionInfo(message.Body);
message.BodyEncoding = Encoding.Unicode;
message.ReplyTo = new MailAddress(Mail);
if (screenshotFlag)
{
CreateScreenshot();
message.Attachments.Add(new Attachment(MailHelper.FeedBackScreenShotPath));
}
return message;
}
-- Sending email
public void SendMessage()
{
using (SmtpClient smtp = CreateSMTP())
{
smtp.Send(MakeMessage(SendWithScreenshot));
}
}
From the documentation:
These methods block while the message is being transmitted.
So while the message is being transmitted, the method blocks. So after the method is done and you've disposed the message instance, you could delete the file.
Of course, it could still have a lock on the file. That is why I would say you should first dispose the SmtpClient and then try to delete the file (so do that after the using block). It should be fine then.
I've seen that the file was holding by the message object, not by smtp object, so I added using block for message, too.
Thanks to all))
BACKGROUND
I have written a little console application that monitors a RabbitMQ queue for emails. Whenever an email is pushed onto the queue, my application would pick up that email, process it and send it.
CODE
Below is the code for my email service, it is what actually sends out the email.
public class MailService : IMailService
{
private readonly SmtpClient _smtpClient = new SmtpClient();
public void SendEmail(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
_smtpClient.SendAsync(emailMessage, null);
}
#region Helpers
private static MailMessage BuildEmailMessage(string toEmail, string subject, string body, bool isHtml)
{
const string fromEmailAddress = "james.brown#world.com";
var emailMessage = new MailMessage(fromEmailAddress, toEmail, subject, body) { IsBodyHtml = isHtml };
return emailMessage;
}
#endregion
}
PROBLEM
I had 2 emails on the RabbitMQ queue, and when I fired up my console application consumer, it threw the following exception after sending the first email (I received that 1st email in my inbox).
An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
I did some digging around, and saw this thread which explains why I got this. Apparently using SendAsync() isn't the way to go because:
After calling SendAsync, you must wait for the e-mail transmission to complete before attempting to send another e-mail message using Send or SendAsync.
So what is the recommend way of going about this? I can create a new instance of the SmtpClient class for each email, but is that really a good idea?
Send the email synchronously, there's no need to use the older async syntax of SendAsync. Also, ensure your SmtpClient only gets hit from one thread at a time by wrapping it in a using statement. There is a slight performance penalty, but you probably won't notice it unless you're sending a ton of emails. And if you are sending a ton, then overload your MailService.SendEmail method to accept an IEnumerable<EmailModel> and send them all at once using a single SmtpClient.
public void SendEmail(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
using(var client = new SmtpClient())
{
_smtpClient.Send(emailMessage);
}
}
//this would be the right way to do async
public async Task SendEmailAsync(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
using(var client = new SmtpClient())
{
_smtpClient.SendMailAsync(emailMessage);
}
}
//this would be the right way to do multiple emails
//you'd need to create an EmailModel class to contain all the details for each email (similar to MailMessage, but it would prevent your own code from taking a dependency on System.Net.Mail
public void SendEmail(IEnumerable<EmailModel> emailModels)
{
var mailMessages = emailModels.Select(em => ConvertEmailModelToMailMessage(em));
using(var client = new SmtpClient())
{
foreach(var mailMessage in mailMessages)
{
//you may want some error handling on the below line depending on whether you want all emails to attempt to send even if one encounters an error
_smtpClient.Send(mailMessage);
}
}
}
private MailMessage ConvertEmailModelToMailMessage(EmailModel emailModel)
{
//do conversion here
}
In my application I have a functionality to save and publish articles. So when I click on "Save and Publish" button three things happened:
Published articles get saved in database.
A Notification email goes to a group of users that a new articles is available.
After sending emails page get redirect to "Article Listing" page without showing any success or failure message for an email.
Now Number of users who will receive emails can vary say for e.g 10, 30 50 and so on. I want to send notification emails asynchronously so that page won't get block until all the mails doesn't go to their receptionists.
Given below is a piece of code from "PublishArticle" action method
foreach (string to in emailIds)
{
ArticleNotificationDelegate proc = Email.Send;
IAsyncResult asyncResult = proc.BeginInvoke(subject, body, to, from, cc, null, null, null);
}
Below I have defined a delegate to invoke Send method
private delegate bool ArticleNotificationDelegate (string subject, string body, string to, string from, string cc, string bcc = null);
and this is the code to send an email:
public static bool Send(string subject, string body, string to, string from, string cc, string bcc = null)
{
bool response;
MailMessage mail = new MailMessage();
MailAddress fromAddress = new MailAddress(from);
mail.To.Add(to);
if (!string.IsNullOrWhiteSpace(cc))
{
mail.CC.Add(cc);
}
if (!string.IsNullOrWhiteSpace(bcc))
{
mail.Bcc.Add(bcc);
}
mail.From = fromAddress;
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
mail.Priority = MailPriority.High;
SmtpClient client = new SmtpClient();
try
{
client.Send(mail);
response = true;
}
catch (Exception)
{
response = false;
}
finally
{
client.Dispose();
mail.Dispose();
}
return response;
}
Although this code is working fine but still I want to know that whether my this approach is fine and will not cause any problem in future.
If there is a better approach to accomplish my objective then please suggest me.
Note: As I am using .net framework 4.0 so cannot use the new features of Asyn and await available in 4.5.
Also I had used method client.SendAsync by simply replacing the client.Send and rest of my code in above Send method was same. After this change NO mails were being send and also it did not throw any exception. So I did not go with this change.
I want to send notification emails asynchronously so that page won't get block until all the mails doesn't go to their receptionists.
That's a very dangerous approach, because ASP.NET will feel free to tear down your app domain if there are no active requests. ASP.NET doesn't know that you've queued work to its thread pool (via BeginInvoke). I recommend that you use a solution like HangFire to reliably send email.
I am working on web form which collects certain user information from users and sends confirmation by email. I am trying to user the following approach to send the HTML email as it make managing HTML based email easy.
https://gist.github.com/1668751
I made necessary changes to the code but it is not working. I read other related article to make it work but i am doing something wrong.
Following line of code generates error The replacements dictionary must contain only strings.
MailMessage msgHtml = mailDef.CreateMailMessage(to, replacements, MessageBody, new System.Web.UI.Control());
I have made many change to the code but it doesnt seem to work for me. I would appreciate help to make this code work.
If i comment the above line of code with some other changes then i can send email but i can't replace the token. Any easy approach to replace token is also welcome.
Below is the Complete code i am using right now
String to, subject, Name;
subject = "Booking Confirmation";
Name = txtName.text;
ListDictionary replacements = new ListDictionary();
replacements.Add("<%Name%>", Name);
replacements.Add("<%Email%>", objVR.Email);
replacements.Add("<%CompanyName%>", objVR.CompanyName);
replacements.Add("<%BookingDate%>", objVR.BookingDate);
replacements.Add("<%BookingTime%>", objVR.TimeSlot);
replacements.Add("<%NoOfVisitors%>", objVR.NoOfVisitors);
replacements.Add("<%BookingCode%>", objVR.BookingUniqueID);
MailDefinition mailDef = new MailDefinition();
string MessageBody = String.Empty;
string filePath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
using (StreamReader sr = new StreamReader(filePath + #"\en\VREmailEnglish.htm"))
{
MessageBody = sr.ReadToEnd();
}
MailMessage msgHtml = mailDef.CreateMailMessage(to, replacements, MessageBody, new System.Web.UI.Control());
string message = msgHtml.Body.ToString();
Helper.SendTokenEmail(to, subject, msgHtml, isHtml);
public static void SendTokenEmail(string to, string subject, string mailMessage, bool isHtml)
{
try
{
// Create a new message
var mail = new MailMessage();
// Set the to and from addresses.
mail.From = new MailAddress("noreply#somedomain.net");
mail.To.Add(new MailAddress(to));
// Define the message
mail.Subject = subject;
mail.IsBodyHtml = isHtml;
mail.Body = mailMessage.ToString();
//Object userState = mailMessage;
// Create a new Smpt Client using Google's servers
var mailclient = new SmtpClient();
mailclient.Host = "mail.XYZ.net";
//mailclient.Port = 587; //ForGmail
mailclient.Port = 2525;
mailclient.EnableSsl = false;
mailclient.UseDefaultCredentials = true;
// Specify your authentication details
mailclient.Credentials = new System.Net.NetworkCredential("noreply#somedomain.net", "XYZPassword");
mailclient.Send(mail);
mailclient.Dispose();
}
catch (Exception ex)
{
}
}
As pointed out by HatSoft the ListDictionary accepts objects as key and value so this looks like it should work.
But reading the docs for the CreateMailMessage() method here http://msdn.microsoft.com/en-us/library/0002kwb2.aspx indicates you need to convert the value to a string otherwise it will throw an ArgumentException.
So to fix make sure all values you add to the ListDictionary are converted to string i.e
objVR.BookingDate.ToString()
Here is the code which calls the sendmail method. The problem is that only the first call of sendmail sends the mail to the receiver. The second time when sendmail is called , it gets executed perfectly but never delivers any mail. If I put the application in debug mode and then execute it step by step both the mails get delivered. It seemed like the execution speed of the program is so fast that something goes wrong. Therefore I kept a delay below send function, so it started working fine for me, But I don't think it is a perfect solution. Anybody has any clue what is going on here.
if (!String.IsNullOrEmpty(SendMailAdmin))
{
SendMail(SendMailFrom, SendMailAdmin, Subject, AdminMessageText + "<br>" + MessageText);
}
if (!String.IsNullOrEmpty(SendMailOwner))
{
SendMail(SendMailFrom, SendMailOwner, Subject, OwnerMessageText + "<br>" + MessageText);
}
public void SendMail(String MessageFrom, String MessageTo, String MessageSubject, String MessageBody)
{
MailMessage Message = new MailMessage();
Message.Priority = MailPriority.High;
Message.From = new MailAddress(MessageFrom);
Message.To.Add(MessageTo);
Message.Subject = MessageSubject;
Message.IsBodyHtml = true;
Message.Body = MessageBody;
try
{
SmtpClient client = new SmtpClient(SMTPServer, Convert.ToInt32(SMTPPort));
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("{myusername}", "{mypassword}");
client.Send(Message);
System.Threading.Thread.Sleep(3000);
}
catch
{
throw;
}
}
I personally think the only thing that'll work for you at this point is the delay code .#Shadow is right , this is how servers are configured