EmailUtils.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net.Mail;
  9. using System.Reflection;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows.Controls;
  13. using System.Windows;
  14. using System.Windows.Forms;
  15. using System.Drawing;
  16. using InABox.WPF;
  17. using MessageBox = System.Windows.Forms.MessageBox;
  18. using TextBox = System.Windows.Controls.TextBox;
  19. using InABox.Wpf.Reports;
  20. using System.Diagnostics.CodeAnalysis;
  21. namespace InABox.Wpf;
  22. public static class EmailUtils
  23. {
  24. /// <summary>
  25. /// Creates and opens an email with the default email app - selected by the user.
  26. /// This method is for emails with a PDF attachment. Provide the file name and data.
  27. /// Optionally provide from, subject and body.
  28. /// 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)
  29. /// </summary>
  30. /// <param name="attachmentname"></param>
  31. /// <param name="attachmentdata"></param>
  32. /// <param name="from"></param>
  33. /// <param name="subject"></param>
  34. /// <param name="body"></param>
  35. public static void CreateEMLFile(string attachmentname, byte[] attachmentdata, string from = "", string subject = "", string body = "", string to = "")
  36. {
  37. var message = CreateMessage(from, subject, body, to);
  38. message = AddAttachment(message, attachmentname, attachmentdata);
  39. OpenEmail(message, attachmentname);
  40. }
  41. /// <summary>
  42. /// Creates and opens an email with the default email app - selected by the user.
  43. /// This method is for emails with multiple PDF attachments. Provide the a Dictionary of names and byte arrays
  44. /// Optionally provide from, subject and body.
  45. /// 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)
  46. /// </summary>
  47. /// <param name="attachmentname"></param>
  48. /// <param name="attachmentdata"></param>
  49. /// <param name="from"></param>
  50. /// <param name="subject"></param>
  51. /// <param name="body"></param>
  52. public static void CreateEMLFile(Dictionary<string,byte[]> attachments, string from = "", string subject = "", string body = "", string to = "")
  53. {
  54. var message = CreateMessage(from, subject, body, to);
  55. foreach (var key in attachments.Keys)
  56. AddAttachment(message, key, attachments[key]);
  57. OpenEmail(message);
  58. }
  59. /// <summary>
  60. /// Creates and opens an email with the default email app - selected by the user.
  61. /// This method is for emails with no attachments.
  62. /// Optionally provide from, subject and body.
  63. /// 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)
  64. /// </summary>
  65. /// <param name="from"></param>
  66. /// <param name="subject"></param>
  67. /// <param name="body"></param>
  68. public static void CreateEMLFile(string? from, string? subject, string? body)
  69. {
  70. var message = CreateMessage(from, subject, body);
  71. OpenEmail(message, "Message from " + message.From);
  72. }
  73. public static void OpenEmail(MailMessage message, string? name = null)
  74. {
  75. var filename = Path.Combine(
  76. Path.GetTempPath(),
  77. Path.ChangeExtension(String.IsNullOrWhiteSpace(name) ? Guid.NewGuid().ToString() : name, ".eml")
  78. );
  79. using (var filestream = File.Open(filename, FileMode.Create))
  80. {
  81. var binaryWriter = new BinaryWriter(filestream);
  82. //Write the Unsent header to the file so the mail client knows this mail must be presented in "New message" mode
  83. binaryWriter.Write(Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
  84. var assembly = typeof(SmtpClient).Assembly;
  85. var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter")!;
  86. // Get reflection info for MailWriter contructor
  87. var mailWriterConstructor =
  88. mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Stream), typeof(bool) }, null)!;
  89. // Construct MailWriter object with our FileStream
  90. var mailWriter = mailWriterConstructor.Invoke(new object[] { filestream, true });
  91. // Get reflection info for Send() method on MailMessage
  92. var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic)!;
  93. sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null);
  94. // Finally get reflection info for Close() method on our MailWriter
  95. var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic)!;
  96. // Call close method
  97. closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
  98. }
  99. // Open the file with the default associated application registered on the local machine
  100. Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true });
  101. }
  102. public static MailMessage CreateMessage(string? from = null, string? subject = null, string? body = null, string? to = null)
  103. {
  104. return new MailMessage(
  105. from.NotWhiteSpaceOr(GetAddressFromUser()).NotWhiteSpaceOr("example@outlook.com.au"),
  106. to.NotWhiteSpaceOr("example@outlook.com.au"),
  107. subject.NotWhiteSpaceOr("Enter subject"),
  108. body.NotWhiteSpaceOr("Enter message"))
  109. {
  110. IsBodyHtml = false
  111. };
  112. }
  113. public static string GetAddressFromUser()
  114. {
  115. if(TryGetAddressFromUser(out var address))
  116. {
  117. return address;
  118. }
  119. else
  120. {
  121. MessageWindow.ShowMessage("Current User Email Address is blank - please fill in (Human Resources -> User Accounts -> Choose your User -> Email Settings -> Email Address", "Error");
  122. return "";
  123. }
  124. }
  125. public static string? GetAddressFromUserOrNull()
  126. {
  127. TryGetAddressFromUser(out var address);
  128. return address;
  129. }
  130. public static bool TryGetAddressFromUser([NotNullWhen(true)] out string? address)
  131. {
  132. var table = Client.Query(new Filter<User>(x => x.ID).IsEqualTo(ClientFactory.UserGuid), Columns.None<User>().Add(x => x.EmailAddress));
  133. var user = table.ToObjects<User>().FirstOrDefault();
  134. address = user?.EmailAddress.NotWhiteSpaceOr(null);
  135. return address is not null;
  136. }
  137. public static MailMessage AddAttachment(this MailMessage message, string attachmentname, byte[] attachmentdata)
  138. {
  139. var attachment = Path.Combine(
  140. Path.GetTempPath(),
  141. String.IsNullOrWhiteSpace(Path.GetExtension(attachmentname))
  142. ? Path.ChangeExtension(attachmentname, ".pdf")
  143. : attachmentname
  144. );
  145. File.WriteAllBytes(attachment, attachmentdata);
  146. message.Attachments.Add(new Attachment(attachment));
  147. return message;
  148. }
  149. }