Distribute RDLC Output as Email Attachment

In our winforms application, the print option has long been allowed, which mainly uses RDLC.

The client asked to add a feature that allows users to send "printed" output by email.

Now we know that the EMF file is created (in the TEMP folder) as a kind of hidden by-product of our current printing process.

In our opinion, we can just grab this EMF file and attach it to a new email and complete the task.

  • This is the best variant?
  • Can we rely on opening the EMF file on any Windows machine?
  • How do we identify the EMF file? ... it looks like it is now called %TEMP%\DiaryGrid_1.emf . So, DiaryGrid is the name of our RDLC file, but _1 is added somewhere along the way.
+4
source share
1 answer

I have done this before. I did this by exporting the report programmatically in pdf to a specific place, then we send the PDF file by email and delete it. I will try to find a code for you (not at home now)

Edition:

Sorry for the later version. Now I am at home, and I will give you a few blocks of code that I think will give you some help to complete your task. I will add some comments to the code so that you can understand some things specific to my project. This code has been tested and works well for my clients, but I'm sure it can be improved. Please let me know if you can improve this code;)

First of all, we export the report in pdf.

 private string ExportReportToPDF(string reportName) { Warning[] warnings; string[] streamids; string mimeType; string encoding; string filenameExtension; byte[] bytes = ReportViewer1.LocalReport.Render( "PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings); string filename = Path.Combine(Path.GetTempPath(), reportName); using (var fs = new FileStream(filename, FileMode.Create)) { fs.Write(bytes, 0, bytes.Length); fs.Close(); } return filename; } 

Now we need a class that controls the mail system. Each mail system has its own characteristics, so you may need to change this class. Class behavior is simple. You only need to fill in the properties and call the submit method. In my case, the windows do not allow me to delete the PDF file after it is sent (Windows says that the file is being used), so I program the file that will be deleted the next time I reboot. Take a look at the removal method. Note that the submit method uses the cutom class named MailConfig. This is a small class that has some configuration lines, such as Host, User Name and Password. Mail will be sent using these parameters.

 public class Mail { public string Title { get; set; } public string Text { get; set; } public string From { get; set; } public bool RequireAutentication { get; set; } public bool DeleteFilesAfterSend { get; set; } public List<string> To { get; set; } public List<string> Cc { get; set; } public List<string> Bcc { get; set; } public List<string> AttachmentFiles { get; set; } #region appi declarations internal enum MoveFileFlags { MOVEFILE_REPLACE_EXISTING = 1, MOVEFILE_COPY_ALLOWED = 2, MOVEFILE_DELAY_UNTIL_REBOOT = 4, MOVEFILE_WRITE_THROUGH = 8 } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); #endregion public Mail() { To = new List<string>(); Cc = new List<string>(); Bcc = new List<string>(); AttachmentFiles = new List<string>(); From = MailConfig.Username; } public void Send() { var client = new SmtpClient { Host = MailConfig.Host, EnableSsl = false, }; if (RequireAutentication) { var credentials = new NetworkCredential(MailConfig.Username, MailConfig.Password); client.Credentials = credentials; } var message = new MailMessage { Sender = new MailAddress(From, From), From = new MailAddress(From, From) }; AddDestinataryToList(To, message.To); AddDestinataryToList(Cc, message.CC); AddDestinataryToList(Bcc, message.Bcc); message.Subject = Title; message.Body = Text; message.IsBodyHtml = false; message.Priority = MailPriority.High; var attachments = AttachmentFiles.Select(file => new Attachment(file)); foreach (var attachment in attachments) message.Attachments.Add(attachment); client.Send(message); if (DeleteFilesAfterSend) AttachmentFiles.ForEach(DeleteFile); } private void AddDestinataryToList(IEnumerable<string> from, ICollection<MailAddress> mailAddressCollection) { foreach (var destinatary in from) mailAddressCollection.Add(new MailAddress(destinatary, destinatary)); } private void DeleteFile(string filepath) { // this should delete the file in the next reboot, not now. MoveFileEx(filepath, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); } } 

Now you can create a form to query destinataries, add some validation, etc., return an instance of the Mail class to you ... or simply "hard-code" the values ​​and populate the class.

Here is the code that I use the button to call this form, in my example it is called SendMailView.

 private void BtnSendByMail_Click(object sender, EventArgs e) { SendMailView sendMailView = new SendMailView(); if (sendMailView.ShowDialog()== DialogResult.OK) { Mail mail = sendMailView.CurrentItem; mail.AttachmentFiles.Add(ExportReportToPDF("Invoice.pdf")); mail.DeleteFilesAfterSend = true; mail.RequireAutentication = true; mail.Send(); } sendMailView.Dispose(); } 

In this example, senMailView.CurrentItem is an instance of the mail class. We just need to call Send metis and get the job done.

This is the biggest answer I've ever written in SO ... I hope it helps you: D If you have problems using it, call me. By the way, I'm not very proud of my English, so forgive me if the text has any error.

+8
source

All Articles