SMTPException 其中一个流已被使用,无法重置为原点

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

当我尝试通过我的 C# 代码向多个收件人发送一封带有附件的电子邮件时,抛出一个 System.Net.Mail.SmtpException 说 "Failure sending mail." 内部异常是 "One of the streams has already been used and can't be reset to the origin."

我理解这种错误可能是我的执着造成的。 我在不同的 class 中创建了我的附件,如 -

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

我将以这种格式将其发送到发送电子邮件的 class。 class -

中发生以下情况
try
{    
     email.Subject = subject;
     email.Body = body;
     if (file != null)
     {
         email.Attachments.Add(file);
     }
    _smtpClient.Send(email);
}   
catch
{
     mailSent = false;
}

邮件总是发送给第一个收件人,但对其余所有收件人均失败。 知道为什么会发生这种情况吗?

Attachment class 内部,它似乎使用 Stream 来包含数据。某些类型的流不允许您将位置重置回开始位置,并且会抛出一个 InvalidOperationException 以及您在上面看到的消息。

您的解决方案是:

  1. 发送一封邮件,但将所有收件人放在 Bcc 字段中。
  2. 为您发送的每封邮件创建附件 - 不要每次都重复使用相同的对象。
  3. 这可能行不通,但您可以尝试使用 Attachment 的构造函数,它将流而不是字符串作为参数。将所有字符串数据放入允许重新定位的 MemoryStream 中。例如:

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

    然后这个:

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

注意:您错误地初始化了附件对象。在带有两个 string 参数的 constructor 中,第二个参数是媒体类型,而不是文件名。

在我们的例子中,它是 LinkedResource 实例(文件附件,作为内联图像嵌入到电子邮件中)被重复用于多条消息。消息在发送后 .Dispose' - 这关闭了所有底层流。

我想这基本上可以归结为@DavidG 的回答,只需加上我的两分钱 - 请记住检查嵌入式资源,而不仅仅是普通附件。