using InABox.Clients; using InABox.Core; using InABox.Reports; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Mail; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows; using System.Windows.Forms; using System.Drawing; using InABox.WPF; using MessageBox = System.Windows.Forms.MessageBox; using Comal.Classes; using TextBox = System.Windows.Controls.TextBox; using InABox.Wpf.Reports; namespace PRSDesktop { public class EmailUtils { /// /// Creates and opens an email with the default email app - selected by the user. /// This method is for emails with a PDF attachment. Provide the file name and data. /// Optionally provide from, subject and body. /// If from is not provided, an attempt will be made to find the User's email address - if empty it will throw an error (cannot be empty) /// /// /// /// /// /// public static void CreateEMLFile(string attachmentname, byte[] attachmentdata, string from = "", string subject = "", string body = "", string to = "") { var message = CreateMessage(from, subject, body, to); message = AddAttachment(message, attachmentname, attachmentdata); OpenEmail(message, attachmentname); } /// /// Creates and opens an email with the default email app - selected by the user. /// This method is for emails with multiple PDF attachments. Provide the a Dictionary of names and byte arrays /// Optionally provide from, subject and body. /// If from is not provided, an attempt will be made to find the User's email address - if empty it will throw an error (cannot be empty) /// /// /// /// /// /// public static void CreateEMLFile(Dictionary attachments, string from = "", string subject = "", string body = "", string to = "") { var message = CreateMessage(from, subject, body, to); foreach (var key in attachments.Keys) AddAttachment(message, key, attachments[key]); OpenEmail(message); } /// /// Creates and opens an email with the default email app - selected by the user. /// This method is for emails with no attachments. /// Optionally provide from, subject and body. /// If from is not provided, an attempt will be made to find the User's email address - if empty it will throw an error (cannot be empty) /// /// /// /// public static void CreateEMLFile(string from = "", string subject = "", string body = "") { var message = CreateMessage(from, subject, body); OpenEmail(message, "Message from " + from); } private static void OpenEmail(MailMessage message, string name = null) { var filename = Path.Combine( Path.GetTempPath(), Path.ChangeExtension(String.IsNullOrWhiteSpace(name) ? Guid.NewGuid().ToString() : name, ".eml") ); using (var filestream = File.Open(filename, FileMode.Create)) { var binaryWriter = new BinaryWriter(filestream); //Write the Unsent header to the file so the mail client knows this mail must be presented in "New message" mode binaryWriter.Write(Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine)); var assembly = typeof(SmtpClient).Assembly; var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter")!; // Get reflection info for MailWriter contructor var mailWriterConstructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Stream), typeof(bool) }, null)!; // Construct MailWriter object with our FileStream var mailWriter = mailWriterConstructor.Invoke(new object[] { filestream, true }); // Get reflection info for Send() method on MailMessage var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic)!; sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null); // Finally get reflection info for Close() method on our MailWriter var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic)!; // Call close method closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null); } // Open the file with the default associated application registered on the local machine Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true }); } private static MailMessage CreateMessage(string from, string subject, string body, string to = "") { if (string.IsNullOrWhiteSpace(to)) to = "example@outlook.com.au"; if (string.IsNullOrWhiteSpace(from)) from = GetAddressFromUser(); if (string.IsNullOrWhiteSpace(subject)) subject = "Enter subject"; if (string.IsNullOrWhiteSpace(body)) body = "Enter message"; var message = new MailMessage(from, to, subject, body); message.IsBodyHtml = false; return message; } private static string GetAddressFromUser() { CoreTable table = new Client().Query(new Filter(x => x.ID).IsEqualTo(ClientFactory.UserGuid) , new Columns(x => x.EmailAddress)); User user = table.Rows.FirstOrDefault().ToObject(); if (!string.IsNullOrWhiteSpace(user.EmailAddress)) return user.EmailAddress; else MessageBox.Show("Current User Email Address is blank - please fill in (Human Resources -> User Accounts -> Choose your User -> Email Settings -> Email Address", "Error"); return ""; } private static MailMessage AddAttachment(MailMessage message, string attachmentname, byte[] attachmentdata) { var attachment = Path.Combine( Path.GetTempPath(), String.IsNullOrWhiteSpace(Path.GetExtension(attachmentname)) ? Path.ChangeExtension(attachmentname, ".pdf") : attachmentname ); File.WriteAllBytes(attachment, attachmentdata); message.Attachments.Add(new Attachment(attachment)); return message; } public static IEnumerable CreateTemplateDefinitions(DataModel model) { var templates = new Client().Query(new Filter(x => x.Model).IsEqualTo(model.Name) .And(x => x.Visible).IsEqualTo(true)); if (templates.Rows.Any()) { List list = new List(); foreach (CoreRow row in templates.Rows) { Action action = new Action((model, data) => { DoEmailAction(model, data, row.Get(x => x.Name)); }); list.Add( new ReportExportDefinition( "Email Report", ImageUtils.CreatePreviewWindowButtonContent(row.Get(x => x.Name),PRSDesktop.Resources.emailreport), ReportExportType.PDF, action)); } return list; } else return new List() { new ReportExportDefinition( "Email Report", ImageUtils.CreatePreviewWindowButtonContent("Email",PRSDesktop.Resources.emailreport), ReportExportType.PDF, DoEmailReport) }; } private static void DoEmailAction(DataModel model, byte[] data, string templateName) { var template = new Client().Query(new Filter(x => x.Name).IsEqualTo(templateName)).Rows.FirstOrDefault(); ParseTemplateAndCreateEmail(template, model, data); } private static void ParseTemplateAndCreateEmail(CoreRow row, DataModel model, byte[] data) { var to = DataModelUtils.ParseTemplate(model, row.Get(x => x.To)).Replace("\n", "").Replace("\r", ""); var Subject = DataModelUtils.ParseTemplate(model, row.Get(x => x.Subject)).Replace("\n", "").Replace("\r", ""); var attachmentName = DataModelUtils.ParseTemplate(model, row.Get(x => x.AttachmentName)).Replace("\n", "").Replace("\r", ""); var body = DataModelUtils.ParseTemplate(model, row.Get(x => x.Template)); if (string.IsNullOrWhiteSpace(attachmentName)) attachmentName = model.Name; EmailUtils.CreateEMLFile(attachmentName, data, App.EmployeeEmail, Subject, body, to); } public static void DoEmailReport(DataModel model, byte[] data) { string attachmentName = DetermineName(model); EmailUtils.CreateEMLFile(attachmentName, data, App.EmployeeEmail, "Emailing report for " + attachmentName); } private static string DetermineName(DataModel model) { string title = model.Name; if (model.HasTable()) { CoreTable table = model.GetTable(); title = title + " - " + table.Rows.FirstOrDefault().Get(x => x.Title); } else if (model.HasTable()) { title = "Purchase Order "; CoreTable table = model.GetTable(); if (table.Rows.Count == 1) title += table.Rows.FirstOrDefault().Get(x => x.PONumber); else if (table.Rows.Count > 1) { foreach (CoreRow row in table.Rows) { title = title + row.Get(x => x.PONumber) + ", "; } title = title.Substring(0, title.Length - 2); } } return title; } } }