Browse Source

PRS SHARED - added EmailUtils class and static functions for sending emails

Nick-PRSDigital@bitbucket.org 2 years ago
parent
commit
9892c096d4
2 changed files with 124 additions and 0 deletions
  1. 123 0
      prs.shared/EmailUtils.cs
  2. 1 0
      prs.shared/PRS.Shared.csproj

+ 123 - 0
prs.shared/EmailUtils.cs

@@ -0,0 +1,123 @@
+
+using System.Diagnostics;
+using System.IO;
+using System.Net.Mail;
+using System.Reflection;
+using System.Text;
+using InABox.Clients;
+using InABox.Core;
+
+namespace PRS.Shared
+{
+    public class EmailUtils
+    {
+        /// <summary>
+        /// 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)
+        /// </summary>
+        /// <param name="attachmentname"></param>
+        /// <param name="attachmentdata"></param>
+        /// <param name="from"></param>
+        /// <param name="subject"></param>
+        /// <param name="body"></param>
+        public static void CreateEMLFile(string attachmentname, byte[] attachmentdata, string from = "", string subject = "", string body = "")
+        {
+            var message = CreateMessage(from, subject, body);
+
+            message = AddAttachment(message, attachmentname, attachmentdata);
+
+            OpenEmail(message, attachmentname);
+        }
+
+        /// <summary>
+        /// 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)
+        /// </summary>
+        /// <param name="from"></param>
+        /// <param name="subject"></param>
+        /// <param name="body"></param>
+        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)
+        {
+            var filename = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(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)
+        {
+            var message = new MailMessage();
+            if (string.IsNullOrWhiteSpace(from))
+                from = GetAddressFromUser();
+            message.From = new MailAddress(from);
+            message.Subject = subject;
+            message.IsBodyHtml = true;
+            message.Body = body;
+            return message;
+        }
+
+        private static string GetAddressFromUser()
+        {
+            CoreTable table = new Client<User>().Query(new Filter<User>(x => x.ID).IsEqualTo(ClientFactory.UserGuid)
+                , new Columns<User>(x => x.EmailAddress));
+            User user = table.Rows.FirstOrDefault().ToObject<User>();
+
+            if (!string.IsNullOrWhiteSpace(user.EmailAddress))
+                return user.EmailAddress;
+            else
+                MessageBox.Show("Unable to send email. Current User Email Address is blank - please fill in", "Error");
+
+            return "";
+
+        }
+
+        private static MailMessage AddAttachment(MailMessage message, string attachmentname, byte[] attachmentdata)
+        {
+            var attachment = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(attachmentname, ".pdf"));
+            File.WriteAllBytes(attachment, attachmentdata);
+
+            message.Attachments.Add(new Attachment(attachment));
+
+            return message;
+        }
+    }
+}

+ 1 - 0
prs.shared/PRS.Shared.csproj

@@ -39,6 +39,7 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
+    <Folder Include="Email\" />
     <Folder Include="Resources\" />
     <Folder Include="Resources\" />
   </ItemGroup>
   </ItemGroup>