using InABox.Clients; using InABox.Core; 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 TextBox = System.Windows.Controls.TextBox; using InABox.Wpf.Reports; using System.Diagnostics.CodeAnalysis; namespace InABox.Wpf; public static 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 " + message.From); } public 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 }); } public static MailMessage CreateMessage(string? from = null, string? subject = null, string? body = null, string? to = null) { return new MailMessage( from.NotWhiteSpaceOr(GetAddressFromUser()).NotWhiteSpaceOr("example@outlook.com.au"), to.NotWhiteSpaceOr("example@outlook.com.au"), subject.NotWhiteSpaceOr("Enter subject"), body.NotWhiteSpaceOr("Enter message")) { IsBodyHtml = false }; } public static string GetAddressFromUser() { if(TryGetAddressFromUser(out var address)) { return address; } else { MessageWindow.ShowMessage("Current User Email Address is blank - please fill in (Human Resources -> User Accounts -> Choose your User -> Email Settings -> Email Address", "Error"); return ""; } } public static string? GetAddressFromUserOrNull() { TryGetAddressFromUser(out var address); return address; } public static bool TryGetAddressFromUser([NotNullWhen(true)] out string? address) { var table = Client.Query(new Filter(x => x.ID).IsEqualTo(ClientFactory.UserGuid), Columns.None().Add(x => x.EmailAddress)); var user = table.ToObjects().FirstOrDefault(); address = user?.EmailAddress.NotWhiteSpaceOr(null); return address is not null; } public static MailMessage AddAttachment(this 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; } }