1
votes

I have a problem I've not run into before, and can't seem to find any similar issues when I search.

My issue is this.

I have an email method which attaches a PDF using a memory stream, then sends the email using the SendAsync method. Very rarely though, the attachment is attached to a different users email.

This has only happened on extremely rare occasions, and seems to be caused when two emails are sent at exactly the same moment, and even then it's rare that it happens.

The problem is that, no matter how rare, it should not be happening so I'd like to fix it.

The PDF is generated by downloading the results of a URL which returns a PDF, into a WebClient object, then using reading the results of the WebClient.DownloadData method into a memory stream. The memory stream is then attached to an MailMessage object and sent using an SMTPClient object's SendAsync method.

As I said, the problem occurs very infrequently, unfortunately making it very difficult to test.

Here is an example of my code (no actual values, just an example of how it is created, in a cut down way, ie no error trapping etc):

var mailMessage = new MailMessage("[email protected]", "[email protected]", "Subject");
var smtpClient = new SmtpClient();

mailMessage.Body = "Test";
var stream = new MemoryStream(new WebClient().DownloadData("test.com"));
var attachment = new Attachment(stream, "filename.pdf", System.Net.Mime.MediaTypeNames.Application.Pdf);

mailMessage.Attachments.Add(attachment);

smtpClient.SendCompleted += new SendCompletedEventHandler(SendCompleteCallback); // this is a method for logging errors etc
smtpClient.SendAsync(mailMessage, "randomGuidToken");

When the problem does happen, only the user who receives both attachments actually gets an email. The other user gets nothing, no email or attachment.

All help is appreciated.

1
Nothing wrong with the client code - as far as I can tell. However it might be worthwhile to investigate server code instead. (How does test.com serve requests ?); Also how is the url (test.com) generated ? - Ondrej Svejdar
Hi Ondrej, thanks for the response. I used test.com as an example. The actual URL points to a page on our site which generates a PDF using Rotativa (C# MVC component which converts MVC Actions to PDF's). The PDF is generated ok as the attachments are correct, just attached to the wrong email. Each PDF generated has some unique values on, which is how I know they are generated correctly. Hope this helps. I wondered whether it is an issue with memory management somewhere with the SendAsync method but I've not run into it before - yaantbarb
If the attachments themselves are correct, what does the "other" mail have attached? Do the two mails have identical attachments (both A or B) or are they switched (A has B's attachment and vice versa)? - Stefan
Is this code shared/called by two different processes? It could be that you need to put some locks around certain parts of the code to prevent processes overwriting each other. - ChrisF
Are these really all local variables in your productive code? Judging from the behavior, the mailMessage variable gets overridden while the program is downloading stream, thus two threads then add attachments to only the secondly created mail, which is then sent. - Stefan

1 Answers

1
votes

I've managed to solve my issue.

It was down to how the SmtpClient and MailMessage classes were being instantiated and disposed of (or not, in this case).

I found out that the original code was creating the SmtpClient and MailMessage objects as a class wide variable, which was initialised in the class constructor, and the only code which handled the disposing of the objects was in the SendAsynCompleted callback method.

I have now changed the code so that the SmtpClient and MailMessage objects are instantiated within each method which needs them within the class, and made sure the objects are disposed of explicitly.

I've also moved away from using the SendAsync method for now and just use the standard Send method (I may look at moving back to the async method but will need to do a lot more testing and refactoring I think).