101

I've asked a couple of questions here but am still having issues. I'd appreciate if you could tell me what I am doing wrong in my code. I run the code above from a ASP.Net page and get "Cannot Access a Closed Stream".

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

Thanks!!!

EDIT:

Just to help somebody looking for the answer to this question, the code to send a pdf file attached to an email without having to physically create the file is below (thanks to Ichiban and 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);
Gus Cavalcanti
  • 10,527
  • 23
  • 71
  • 104
  • 3
    Thanks for asking this question, it's exactly what I was looking for. – Hardwareguy May 09 '10 at 13:40
  • 1
    thanks for the line of the `position=0`. saved me! – Yisroel M. Olewski Jun 20 '12 at 12:39
  • 2
    Exactly what I need works perfectly thank you so much! I was stuck on closing the document but not the stream: writer.CloseStream = false; cleared it up for me. – Baxter Jan 10 '14 at 19:37
  • 2
    @Semil when putting up a bounty on an old question with an accepted answer, you really should indicate somehow what you miss in the answer. – mkl Jul 19 '15 at 07:14
  • writer.CloseStream = false; saved me as well, was missing that in a method that uses iTextSharp to turn HTML to PDF. Before, passing the memorystream to my mail function failed due to the stream being closed. Thanks. – Alec Menconi Oct 02 '15 at 18:15
  • This question may also help somebody. [iText7 Create PDF in memory instead of physical file](https://stackoverflow.com/questions/40540741/itext7-create-pdf-in-memory-instead-of-physical-file/64671854#64671854) – Uriel Fernandez Dec 23 '20 at 17:57

5 Answers5

84

Have you tried:

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"));

If my memory serves me correctly, this solved a similar problem in a previous project.

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

brianng
  • 5,790
  • 1
  • 32
  • 23
  • 1
    The set_CloseStream method is only available in the Java version. This is iTextSharp (.NET) – ichiban Jul 28 '09 at 19:11
  • Sorry, again I haven't used iTextSharp (.NET) in a while, though the version I used definitely had set_CloseStream. – brianng Jul 28 '09 at 19:18
  • 1
    Changed to writer.CloseStream, and included related link. – brianng Jul 28 '09 at 19:23
  • 1
    Brianng, I really appreciate your help. I realize you and Ichiban kind of held my hand through it. Thanks! – Gus Cavalcanti Jul 28 '09 at 22:13
  • If we keep the writer alive, when are we suppose to `writer.Flush()` then? – Blaise Sep 25 '14 at 15:05
  • 1
    `writer.ClosStream = false; doc.Close();` solved the problem, thank you – Hakan Fıstık Jul 28 '16 at 09:48
  • What does "PdfWriter.CloseStream" do? We have old Code, where somebody who is on holiday for the next weeks changed something which made all PDF creation failing. If I set CloseStream to false, everything works like before but I really want to understand why. – The incredible Jan Apr 24 '17 at 14:10
  • @the-incredible-jan PdfWriter.CloseStream tells itext if it may also close the PdfWriter stream when the doc.Close() method is called. [another example to achieve this](https://stackoverflow.com/questions/40540741/itext7-create-pdf-in-memory-instead-of-physical-file/64671854#64671854) – Uriel Fernandez Dec 23 '20 at 18:01
18

I tried the code posted by brianng and it worked. Just change the top of the code to this:

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*/
Community
  • 1
  • 1
ichiban
  • 6,162
  • 3
  • 27
  • 34
  • 3
    Thanks for taking the time to verify! – brianng Jul 28 '09 at 19:48
  • 1
    Hi Ichiban, It compiles and it actually sends the email with the attachment, but the attached pdf document come across with 0kb. Did you actually open the pdf an email sent? – Gus Cavalcanti Jul 28 '09 at 20:37
  • 2
    @Gustavo, the file opens correctly in Acrobat viewer. It is about 900 Bytes. Make sure you keep the line: memoryStream.Position=0; right after doc.Close(). I forgot to mention that. (see update above) – ichiban Jul 28 '09 at 21:39
  • 1
    YES! Thank you so much guys. It finally worked. Since Ichiban's answer was based on brianng's, I think it's fair to mark brianng's answer as correct. – Gus Cavalcanti Jul 28 '09 at 22:11
3

Probably calling doc.Close() Disposes the underlying stream. Try removing doc.Close() and instead of that line set memoryStream.Position = 0;

Alternatively you can use a temp file:

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
  • 14,953
  • 15
  • 56
  • 78
3

Can you flush the document or memory stream and then close it after you attach it?

James Conigliaro
  • 3,809
  • 19
  • 22
  • Hi James. I did this and the result did not change - I still get the "Cannot Access a Closed Stream" error. :( Other ideas? – Gus Cavalcanti Jul 28 '09 at 19:25
1

I had the same problem and I used this post to solve it.In the code written by 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"));

I think instead of writing

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

Just create a new Stream

MemoryStream m = new MemoryStream(memoryStream);

and then call

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

Both work but I think it is better to create the new stream

Zein Sleiman
  • 254
  • 2
  • 11