Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SMTPException One of the streams has already been used and can't be reset to the origin

Tags:

c#

email

smtp

When I'm trying to send an email with attachment with more than one recipients through my C# code an System.Net.Mail.SmtpException is thrown saying "Failure sending mail." The inner exception is "One of the streams has already been used and can't be reset to the origin."

I understand this kind of error maybe happening because of my attachment. I have created my attachment in a different class as -

Attatchment file;
string fileContents = File.ReadAllText(fileName);
file = Attachment.CreateAttachmentFromString(fileContents, fileName);

I'm sending it in this format to my class that sends the email. The following happens in that class -

try
{    
     email.Subject = subject;
     email.Body = body;
     if (file != null)
     {
         email.Attachments.Add(file);
     }
    _smtpClient.Send(email);
}   
catch
{
     mailSent = false;
}

The mail is always sent to the first recipient but fails for all the rest. Any ideas why this could be happening?

like image 976
DeeDeeR Avatar asked Oct 26 '15 09:10

DeeDeeR


2 Answers

Internally to the Attachment class it appears to use a Stream to contain the data. Some types of stream don't allow you to reset the position back to the start and will throw an InvalidOperationException with the message you see above.

Your solutions are:

  1. Send a single mail but put all recipients in the Bcc field.
  2. Create the attachment for each mail you send - do not reuse the same object each time.
  3. This may not work, but you could try using the constructor for Attachment that takes a stream as a parameter instead of string. Put all your string data into a MemoryStream which does allow repositioning. For example:

    public Stream StringToStream(string s)
    {
        MemoryStream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream);
        writer.Write(s);
        writer.Flush();
        stream.Position = 0;
        return stream;
    }
    

    Then this:

    var stream = StringToStream(File.ReadAllText(fileName));
    Attatchment file = new Attachment(stream, fileName);
    

Note: You are initialising the attachment object incorrectly. In the constructor that takes two string parameters, the second parameter is the media type, not the filename.

like image 83
DavidG Avatar answered Oct 23 '22 02:10

DavidG


In our case it was the LinkedResource instance (file-attachment, embedded into an email as an inline image) that was RE-USED for multiple messages. And messages were .Dispose'd after sending - which closed all the underlying streams.

I guess it essentially boils down to @DavidG's answer, just adding my two cents - remember to check embedded resources not just plain attachments.

like image 3
Alex from Jitbit Avatar answered Oct 23 '22 01:10

Alex from Jitbit