Send mail with PDFDocument without filename in C# - c#

i have the following Code :
How can i send the PDFDocument "doc" without saving it (without filename)?
To create an attachment object i need a filename (path), but i dont have one.

Just choose a name for the file
var stream = new MemoryStream();
doc.WriteToStream(stream);
stream.Position = 0;
var contentType = new ContentType(MediaTypeNames.Application.Pdf)
{
Name ="withoutfilename.pdf";
};
var attachment = new Attachment(stream, contentType);
mailMsg.Attachments.Add(attachment);

Related

C# iText7 - 'Trailer Not Found' when using PdfReader with PDF string from database

I'm saving the contents of my PDF file (pdfAsString) to the database.
File is of type IFormFile (file uploaded by the user).
string pdfAsString;
using (var reader = new StreamReader(indexModel.UploadModel.File.OpenReadStream()))
{
pdfAsString = await reader.ReadToEndAsync();
// pdfAsString = ; // encoding function or lack thereof
}
Later I'm trying to fetch and use these contents to initialize a new instance of MemoryStream, then using that to create a PdfReader and then using that to create a PdfDocument, but at this point I get the 'Trailer not found' exception. I have verified that the Trailer part of the PDF is present inside the contents of the string that I use to create the MemoryStream. I have also made sure the position is set to the beginning of the file.
The issue seems related to the format of the PDF contents fetched from the database. iText7 doesn't seem able to navigate through it other than the beginning of the file.
I'm expecting to be able to create an instance of PdfDocument with the contents of the PDF saved to my database.
Note 1: Using the Stream created from OpenReadStream() works when trying to create a PdfReader and then PdfDocument, but I don't have access to that IFormFile when reading from the DB, so this doesn't help me in my use case.
Note 2: If I use the PDF from my device by giving a path, it works correctly, same for using a FileStream created from a path. However, this doesn't help my use case.
So far, I've tried saving it raw and then using that right out of the gate (1) or encoding special symbols like \n \t to ASCII hexadecimal notation (2). I've also tried HttpUtility.UrlEncode on save and UrlDecode after getting the database record (3), and also tried ToBase64String on save and FromBase64String on get (4).
// var pdfContent = databaseString; // 1
// var pdfContent = databaseString.EncodeSpecialCharacters(); // encode special symbols // 2
// var pdfContent = HttpUtility.UrlDecode(databaseString); // decode urlencoded string // 3
var pdfContent = Convert.FromBase64String(databaseString); // decode base64 // 4
using (var stream = new MemoryStream(pdfContent))
{
PdfReader pdfReader = new PdfReader(stream).SetUnethicalReading(true);
PdfWriter pdfWriter = new PdfWriter("new-file.pdf");
PdfDocument pdf = new PdfDocument(pdfReader, pdfWriter); // exception here :(
// some business logic...
}
Any help would be appreciated.
EDIT: on a separate project, I'm trying to run this code:
using (var stream = File.OpenRead("C:\\<path>\\<filename>.pdf"))
{
var formFile = new FormFile(stream, 0, stream.Length, null, "<filename>.pdf");
var reader = new StreamReader(formFile.OpenReadStream());
var pdfAsString = reader.ReadToEnd();
var pdfAsBytes = Encoding.UTF8.GetBytes(pdfAsString);
using (var newStream = new MemoryStream(pdfAsBytes))
{
newStream.Seek(0, SeekOrigin.Begin);
var pdfReader = new PdfReader(newStream).SetUnethicalReading(true);
var pdfWriter = new PdfWriter("Test-PDF-1.pdf");
PdfDocument pdf = new PdfDocument(pdfReader, pdfWriter);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<string, PdfFormField> fields = form.GetFormFields();
foreach (var field in fields)
{
field.Value.SetValue(field.Key);
}
//form.FlattenFields();
pdf.Close();
}
}
and if I replace "newStream" inside of PdfReader with formFile.OpenReadStream() it works fine, otherwise I get the 'Trailer not found' exception.
Answer: use BinaryReader and ReadBytes instead of StreamReader when initially trying to read the data. Example below:
using (var stream = File.OpenRead("C:\\<filepath>\\<filename>.pdf"))
{
// FormFile - my starting point inside of the web application
var formFile = new FormFile(stream, 0, stream.Length, null, "<filename>.pdf");
var reader = new BinaryReader(formFile.OpenReadStream());
var pdfAsBytes = reader.ReadBytes((int)formFile.Length); // store this in the database
using (var newStream = new MemoryStream(pdfAsBytes))
{
newStream.Seek(0, SeekOrigin.Begin);
var pdfReader = new PdfReader(newStream).SetUnethicalReading(true);
var pdfWriter = new PdfWriter("Test-PDF-1.pdf");
PdfDocument pdf = new PdfDocument(pdfReader, pdfWriter);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<string, PdfFormField> fields = form.GetFormFields();
foreach (var field in fields)
{
field.Value.SetValue(field.Key);
}
//form.FlattenFields();
pdf.Close();
}
}

Xlsio Excel file as Mailkit attachement

I'm using Mailkit to send email, and I would like to send a created Excel file (thanks to Xlsio) as an Email attachement.
I achieved to send the email, I see the attachement with good extension (.xlsx) but when I want to open it I have an error "Format or extention is not valid".
This is what I've coded for creating the Excel file
FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
workbook.SaveAs(stream, ExcelSaveType.SaveAsXLS);
FileAttachementDto file = new()
{
FileName = fileName,
File = stream, // Type of File property is Stream
};
What I'v coded for adding the file to the email attachements
var attachements = MimeEntity.Load(
new ContentType("application", "vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
new MemoryStream(myFile.File.ReadAsBytes()));
bodyBuilder.Attachments.Add(attachements);
Thanks
Don't do this:
var attachements = MimeEntity.Load(
new ContentType("application", "vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
new MemoryStream(myFile.File.ReadAsBytes()));
That is for parsing HTTP web responses.
Just do this instead:
var attachment = new MimePart ("application", "vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
FileName = "fileName.xls",
ContentTransferEncoding = ContentEncoding.Base64,
Content = new MimeContent (new MemoryStream (myFile.File.ReadAsBytes ()))
};
We suggest you to set the workbook version as Xlsx before saving the Excel document and remove the ExcelSaveType.SaveAsXLS parameter in SaveAs method of IWorkbook.
Code Snippet:
FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
workbook.Version = ExcelVersion.Xlsx;
workbook.SaveAs(stream);
FileAttachementDto file = new()
{
FileName = fileName,
File = stream, // Type of File property is Stream
};
​​​

Get attachment and save in s3 bucket mailkit imap

I need to get the attachments that are in the email to save, I do the whole process of reading the email and saving as I need to, but when I try to get the attachments to save in the AWS S3 Bucket it gives an error when it tries to read the content type.
Basically what I need to do is.
Get the attachment.
Create a FormFile for my S3 save function to save the attachments (The S3 save function is already working).
I am having problem just to build the FormFile.
.
.
.
var attachmentsToS3 = new FormFileCollection();
foreach (var attachment in message.Attachments)
{
var part = attachment as MimePart;
var stream = new MemoryStream();
await part.Content.DecodeToAsync(stream);
var fileLength = stream.Length;
var formFile = new FormFile(stream, 0, fileLength, "file[]", attachment.ContentDisposition.FileName);
attachmentsToS3.Add(formFile);
}
await _atendimentoServices.SaveAnexoAtendimentoToS3( attachmentsToS3, idAcompanhamento, requestApi);
.
.
.
UPDATE
Changes made based on bruno's answer and it is now working.
var attachmentsToS3 = new FormFileCollection();
foreach (MimeEntity attachment in message.Attachments)
{
var memory = new MemoryStream();
if (attachment is MimePart part)
await part.Content.DecodeToAsync(memory);
else
await ((MessagePart)attachment).Message.WriteToAsync(memory);
var bytes = memory.ToArray();
var contentType = MimeTypes.GetMimeType(attachment.ContentType.MimeType);
var formFile = new FormFile(memory, 0, bytes.Length, "file[]", attachment.ContentDisposition.FileName)
{
Headers = new HeaderDictionary(),
ContentType = contentType
};
attachmentsToS3.Add(formFile);
}
await _atendimentoServices.SaveAnexoAtendimentoToS3(attachmentsToS3, idAcompanhamento, requestApi);```
Good Afternoon Gabriel, Analysing you code I noticed there were missing some parts of code.
the first you need to trate your attachment to like this:
if (attachment is MimePart part) await part.Content.DecodeToAsync(memory);
else await ((MessagePart)attachment).Message.WriteToAsync(memory);
With that you'll garanted your stream will be populated correctly been a mimeType or not.
The other part was missing is the header and the content type at your FormFile constructor, try that.
var formFile = new FormFile(memory, 0, bytes.Length, "file[]", attachment.ContentDisposition.FileName)
{
Headers = new HeaderDictionary(),
ContentType = MimeTypes.GetMimeType(attachment.ContentType.MimeType);
};

How to convert XML to Byte to File/PDF

I have successfully done "find and replace" which created an xml. Now I want to convert the newly created xml file to pdf which will be attached as a file and sent in a mail.
The result of the Base64String was tested on a base64 pdf file converter but the pdf cannot be opened. Got this error: Something went wrong couldn't open the file
HOW CAN I MAKE THIS WORK?
public async Task<string> CreateDocument(string PolicyNumber)
{
var policy = await _context.Policy.SingleOrDefaultAsync(p => p.PolicyNumber == PolicyNumber);
ArgumentNullException.ThrowIfNull(policy, "Policy Not Available");
//CreatePolicyDocument
//create policy document
var files = #"C:\Users\PATHTODOCUMENT\holderTest.docx";
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(files, true))
{
string docText;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
Regex regexText = new Regex("XCONCLUSION_DATEX");
var newWordText = regexText.Replace(docText, "Hi Everyone!");
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(newWordText);
Encoding encoding = Encoding.UTF8;
byte[] docAsBytes = encoding.GetBytes(newWordText);
File.WriteAllBytes("hello.pdf", docAsBytes);
var file = Convert.ToBase64String(docAsBytes);
}
}
//send message
//
return "";
}
PDF file has its own construct,so you can't generate a pdf file with the contentstring of xml file dirctly.
If you really want to convert xml contentstring to PDF,you could try iTextSharp.
I tried with a simple demo,and here's the code:
[HttpPost]
public IActionResult XMLtoPDF([FromForm] Try T1)
{
var streamContent = new StreamContent(T1.file.OpenReadStream());
var filestring = streamContent.ReadAsStringAsync().Result;
MemoryStream outputStream = new MemoryStream();
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
//PDF settings
PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
doc.Open();
var paragraph = new Paragraph(filestring);
doc.Add(paragraph);
doc.Close();
outputStream.Close();
var pdfArray = outputStream.ToArray();
return File(pdfArray, "application/pdf");
}
Result:

Itextsharp SetField not replacing the text as expected in mail attachment .Net C# core

I have a pdf template with below content
First Name: {{FirstName}}
Contact Number: {{ContactNumber}}
Email Id: {{EmailId}}
Address 1: {{Address1}}
Address 2: {{Address2}}
Qualification: {{Qualification}}
Using itextsharp i need to replace the texts which is inside the curly braces to its actual texts. So for that i have coded like this
string formFile = path;
PdfReader reader = new PdfReader(formFile);
MemoryStream stream = new MemoryStream();
PdfStamper stamper = new PdfStamper(reader, stream);
AcroFields fields = stamper.AcroFields;
fields.SetField("{{FirstName}}", objUser.FirstName);
fields.SetField("{{ContactNumber}}", objUser.EmailId);
fields.SetField("{{Address1}}", objUser.AddressLine1);
fields.SetField("{{Address2}}", objUser.AddressLine2);
fields.SetField("{{Qualification}}", objUser.Education);
fields.SetField("{{AppNumber}}", "01A2021"+objUser.UserId.ToString());
stamper.Writer.CloseStream = false;
stamper.FormFlattening = true;
stamper.Close();
stream.Position = 0;
and then created my email attachment using
System.Net.Mime.ContentType contentType = new
System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf);
var coverAttachment = new Attachment(stream, contentType);
coverAttachment.ContentDisposition.FileName = "CoverLetter.pdf";
emailMessage.Attachments.Add(coverAttachment);
But when i check the generated pdf, the texts in the {{}} are NOT getting replaced. Any idea why?

Categories