iTextSharp - 在电子邮件附件中发送内存中的 pdf

Posted

技术标签:

【中文标题】iTextSharp - 在电子邮件附件中发送内存中的 pdf【英文标题】:iTextSharp - Sending in-memory pdf in an email attachment 【发布时间】:2010-11-14 19:51:49 【问题描述】:

我在这里问了几个问题,但仍有问题。如果您能告诉我我在代码中做错了什么,我将不胜感激。我从 ASP.Net 页面运行上面的代码并得到“无法访问封闭的流”。

var doc = new Document();

MemoryStream memoryStream = new MemoryStream();

PdfWriter.GetInstance(doc, memoryStream);
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

doc.Close(); //if I remove this line the email attachment is sent but with 0 bytes 

MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")

    Subject = "subject",
    IsBodyhtml = true,
    Body = "body"
;

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));
SmtpClient smtp = new SmtpClient

    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("username@gmail.com", "my_password")
;

smtp.Send(mm); //the "Cannot Access a Closed Stream" error is thrown here

谢谢!!!

编辑:

只是为了帮助寻找这个问题的答案的人,无需实际创建文件即可发送附加到电子邮件的 pdf 文件的代码如下(感谢 Ichiban 和 Brianng):

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

writer.CloseStream = false;
doc.Close();
memoryStream.Position = 0;

MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")

    Subject = "subject",
    IsBodyHtml = true,
    Body = "body"
;

mm.Attachments.Add(new Attachment(memoryStream, "filename.pdf"));
SmtpClient smtp = new SmtpClient

    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("username@gmail.com", "password")

;

smtp.Send(mm);

【问题讨论】:

感谢您提出这个问题,这正是我想要的。 感谢position=0 的行。救了我! 正是我需要的完美作品,非常感谢!我被困在关闭文档而不是流:writer.CloseStream = false;为我清除它。 @Semil 在对已接受答案的旧问题悬赏时,您确实应该以某种方式指出您在答案中遗漏的内容。 writer.CloseStream = false;也救了我,在使用 iTextSharp 将 HTML 转换为 PDF 的方法中丢失了这一点。之前,由于流被关闭,将内存流传递给我的邮件功能失败。谢谢。 【参考方案1】:

我遇到了同样的问题,我用这个帖子解决了。在brianng写的代码中

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

我认为而不是写作

writer.CloseStream = false and memoryStream.Position = 0;

只需创建一个新流

MemoryStream m = new MemoryStream(memoryStream);

然后调用

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

两者都有效,但我认为创建新流更好

【讨论】:

为什么创建一个新流更好? 不是。这是对内存和 CPU 时间的浪费,因为字节必须从一个复制到另一个。 不记得为什么我说它更好。我想我可能意味着它更清楚。抱歉刚看到这个。好久不见了:)【参考方案2】:

我尝试了brianng 发布的代码,它成功了。只需将代码的顶部更改为:

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream); //capture the object
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));
writer.CloseStream = false; //set the closestream property
doc.close(); //close the document without closing the underlying stream
memoryStream.Position = 0;

/* remainder of your code stays the same*/

【讨论】:

感谢您抽出宝贵时间进行验证! 嗨 Ichiban,它编译并实际发送带有附件的电子邮件,但附加的 pdf 文档遇到 0kb。你真的打开了电子邮件发送的 pdf 文件吗? @Gustavo,文件在 Acrobat 查看器中正确打开。它大约是 900 字节。确保保留以下行:memoryStream.Position=0;就在 doc.Close() 之后。我忘了提那个。 (见上面的更新) 是的!十分感谢大家。它终于奏效了。由于 Ichiban 的回答是基于 brianng 的,我认为将 brianng 的回答标记为正确是公平的。【参考方案3】:

你试过了吗:

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

如果我没记错的话,这解决了之前项目中的类似问题。

见http://forums.asp.net/t/1093198.aspx

【讨论】:

set_CloseStream 方法仅在 Java 版本中可用。这是 iTextSharp (.NET) 对不起,我有一段时间没有使用 iTextSharp (.NET),虽然我使用的版本肯定有 set_CloseStream。 更改为 writer.CloseStream,并包含相关链接。 Brianng,非常感谢您的帮助。我意识到你和 Ichiban 有点牵着我的手穿过它。谢谢! writer.ClosStream = false; doc.Close(); 解决了问题,谢谢【参考方案4】:

可能调用 doc.Close() 处理底层流。尝试删除 doc.Close() 而不是该行 set memoryStream.Position = 0;

您也可以使用临时文件:

var tempFilePath = Path.GetTempFileName();

try 
           
    var doc = new Document();

    PdfWriter.GetInstance(doc, File.OpenWrite(tempFilePath));
    doc.Open();
    doc.Add(new Paragraph("First Paragraph"));
    doc.Add(new Paragraph("Second Paragraph"));

    doc.Close();

    MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")
    
        Subject = "subject",
        IsBodyHtml = true,
        Body = "body"
    ;

    mm.Attachments.Add(new Attachment(tempFilePath, "test.pdf"));
    SmtpClient smtp = new SmtpClient
    
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        Credentials = new NetworkCredential("username@gmail.com", "my_password")
    ;

    smtp.Send(mm);

finally

    File.Delete(tempFilePath);

【讨论】:

huseyint,我按照你的建议做了,并且发送了 pdf 文件,但它只有 15 个字节长。当我尝试打开它时,它已损坏。我觉得你的建议我快到了。还有其他想法吗?谢谢! 然后试试 memoryStream.Flush();在设置位置之前 同样的事情。该文件发送时几乎是空的并且已损坏。 :( 您尝试过“创建临时文件”吗? 我现在正在处理它,很快就会通知您。谢谢!【参考方案5】:

您能否刷新文档或内存流,然后在附加后将其关闭?

【讨论】:

嗨詹姆斯。我这样做了,结果没有改变 - 我仍然收到“无法访问关闭的流”错误。 :( 其他想法?

以上是关于iTextSharp - 在电子邮件附件中发送内存中的 pdf的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Python 数据帧存储在内存中并将其作为 excel 附件发送到特定的电子邮件地址?

vbscript [.net] [vb]从内存流发送包含附件的电子邮件

如何使用 InputStream 和 Spring 发送带附件的电子邮件?

如何使用 SmtpClient.SendAsync 发送带有附件的电子邮件?

从 C# 发送带有附件的电子邮件,附件在 Thunderbird 中作为第 1.2 部分到达

使用 PHP 在电子邮件中发送多个附件