EmailUtils.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using InABox.Reports;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Net.Mail;
  10. using System.Reflection;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Controls;
  14. using System.Windows;
  15. using System.Windows.Forms;
  16. using System.Drawing;
  17. using InABox.WPF;
  18. using MessageBox = System.Windows.Forms.MessageBox;
  19. using Comal.Classes;
  20. using TextBox = System.Windows.Controls.TextBox;
  21. using InABox.Wpf.Reports;
  22. namespace PRSDesktop
  23. {
  24. public class EmailUtils
  25. {
  26. /// <summary>
  27. /// Creates and opens an email with the default email app - selected by the user.
  28. /// This method is for emails with a PDF attachment. Provide the file name and data.
  29. /// Optionally provide from, subject and body.
  30. /// 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)
  31. /// </summary>
  32. /// <param name="attachmentname"></param>
  33. /// <param name="attachmentdata"></param>
  34. /// <param name="from"></param>
  35. /// <param name="subject"></param>
  36. /// <param name="body"></param>
  37. public static void CreateEMLFile(string attachmentname, byte[] attachmentdata, string from = "", string subject = "", string body = "", string to = "")
  38. {
  39. var message = CreateMessage(from, subject, body, to);
  40. message = AddAttachment(message, attachmentname, attachmentdata);
  41. OpenEmail(message, attachmentname);
  42. }
  43. /// <summary>
  44. /// Creates and opens an email with the default email app - selected by the user.
  45. /// This method is for emails with multiple PDF attachments. Provide the a Dictionary of names and byte arrays
  46. /// Optionally provide from, subject and body.
  47. /// 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)
  48. /// </summary>
  49. /// <param name="attachmentname"></param>
  50. /// <param name="attachmentdata"></param>
  51. /// <param name="from"></param>
  52. /// <param name="subject"></param>
  53. /// <param name="body"></param>
  54. public static void CreateEMLFile(Dictionary<string,byte[]> attachments, string from = "", string subject = "", string body = "", string to = "")
  55. {
  56. var message = CreateMessage(from, subject, body, to);
  57. foreach (var key in attachments.Keys)
  58. AddAttachment(message, key, attachments[key]);
  59. OpenEmail(message);
  60. }
  61. /// <summary>
  62. /// Creates and opens an email with the default email app - selected by the user.
  63. /// This method is for emails with no attachments.
  64. /// Optionally provide from, subject and body.
  65. /// 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)
  66. /// </summary>
  67. /// <param name="from"></param>
  68. /// <param name="subject"></param>
  69. /// <param name="body"></param>
  70. public static void CreateEMLFile(string from = "", string subject = "", string body = "")
  71. {
  72. var message = CreateMessage(from, subject, body);
  73. OpenEmail(message, "Message from " + from);
  74. }
  75. private static void OpenEmail(MailMessage message, string name = null)
  76. {
  77. var filename = Path.Combine(
  78. Path.GetTempPath(),
  79. Path.ChangeExtension(String.IsNullOrWhiteSpace(name) ? Guid.NewGuid().ToString() : name, ".eml")
  80. );
  81. using (var filestream = File.Open(filename, FileMode.Create))
  82. {
  83. var binaryWriter = new BinaryWriter(filestream);
  84. //Write the Unsent header to the file so the mail client knows this mail must be presented in "New message" mode
  85. binaryWriter.Write(Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
  86. var assembly = typeof(SmtpClient).Assembly;
  87. var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter")!;
  88. // Get reflection info for MailWriter contructor
  89. var mailWriterConstructor =
  90. mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(Stream), typeof(bool) }, null)!;
  91. // Construct MailWriter object with our FileStream
  92. var mailWriter = mailWriterConstructor.Invoke(new object[] { filestream, true });
  93. // Get reflection info for Send() method on MailMessage
  94. var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic)!;
  95. sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null);
  96. // Finally get reflection info for Close() method on our MailWriter
  97. var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic)!;
  98. // Call close method
  99. closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
  100. }
  101. // Open the file with the default associated application registered on the local machine
  102. Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true });
  103. }
  104. private static MailMessage CreateMessage(string from, string subject, string body, string to = "")
  105. {
  106. if (string.IsNullOrWhiteSpace(to))
  107. to = "example@outlook.com.au";
  108. if (string.IsNullOrWhiteSpace(from))
  109. from = GetAddressFromUser();
  110. if (string.IsNullOrWhiteSpace(subject))
  111. subject = "Enter subject";
  112. if (string.IsNullOrWhiteSpace(body))
  113. body = "Enter message";
  114. var message = new MailMessage(from, to, subject, body);
  115. message.IsBodyHtml = false;
  116. return message;
  117. }
  118. private static string GetAddressFromUser()
  119. {
  120. CoreTable table = new Client<User>().Query(new Filter<User>(x => x.ID).IsEqualTo(ClientFactory.UserGuid)
  121. , new Columns<User>(x => x.EmailAddress));
  122. User user = table.Rows.FirstOrDefault().ToObject<User>();
  123. if (!string.IsNullOrWhiteSpace(user.EmailAddress))
  124. return user.EmailAddress;
  125. else
  126. MessageBox.Show("Current User Email Address is blank - please fill in (Human Resources -> User Accounts -> Choose your User -> Email Settings -> Email Address", "Error");
  127. return "";
  128. }
  129. private static MailMessage AddAttachment(MailMessage message, string attachmentname, byte[] attachmentdata)
  130. {
  131. var attachment = Path.Combine(
  132. Path.GetTempPath(),
  133. String.IsNullOrWhiteSpace(Path.GetExtension(attachmentname))
  134. ? Path.ChangeExtension(attachmentname, ".pdf")
  135. : attachmentname
  136. );
  137. File.WriteAllBytes(attachment, attachmentdata);
  138. message.Attachments.Add(new Attachment(attachment));
  139. return message;
  140. }
  141. public static IEnumerable<ReportExportDefinition> CreateTemplateDefinitions(DataModel model)
  142. {
  143. var templates = new Client<DataModelTemplate>().Query(new Filter<DataModelTemplate>(x => x.Model).IsEqualTo(model.Name)
  144. .And(x => x.Visible).IsEqualTo(true));
  145. if (templates.Rows.Any())
  146. {
  147. List<ReportExportDefinition> list = new List<ReportExportDefinition>();
  148. foreach (CoreRow row in templates.Rows)
  149. {
  150. Action<DataModel, byte[]> action = new Action<DataModel, byte[]>((model, data) =>
  151. {
  152. DoEmailAction(model, data, row.Get<DataModelTemplate, string>(x => x.Name));
  153. });
  154. list.Add(
  155. new ReportExportDefinition(
  156. "Email Report",
  157. ImageUtils.CreatePreviewWindowButtonContent(row.Get<DataModelTemplate, string>(x => x.Name),PRSDesktop.Resources.emailreport),
  158. ReportExportType.PDF,
  159. action));
  160. }
  161. return list;
  162. }
  163. else
  164. return new List<ReportExportDefinition>()
  165. {
  166. new ReportExportDefinition(
  167. "Email Report",
  168. ImageUtils.CreatePreviewWindowButtonContent("Email",PRSDesktop.Resources.emailreport),
  169. ReportExportType.PDF,
  170. DoEmailReport)
  171. };
  172. }
  173. private static void DoEmailAction(DataModel model, byte[] data, string templateName)
  174. {
  175. var template = new Client<DataModelTemplate>().Query(new Filter<DataModelTemplate>(x => x.Name).IsEqualTo(templateName)).Rows.FirstOrDefault();
  176. ParseTemplateAndCreateEmail(template, model, data);
  177. }
  178. private static void ParseTemplateAndCreateEmail(CoreRow row, DataModel model, byte[] data)
  179. {
  180. var to = DataModelUtils.ParseTemplate(model, row.Get<DataModelTemplate, string>(x => x.To)).Replace("\n", "").Replace("\r", "");
  181. var Subject = DataModelUtils.ParseTemplate(model, row.Get<DataModelTemplate, string>(x => x.Subject)).Replace("\n", "").Replace("\r", "");
  182. var attachmentName = DataModelUtils.ParseTemplate(model, row.Get<DataModelTemplate, string>(x => x.AttachmentName)).Replace("\n", "").Replace("\r", "");
  183. var body = DataModelUtils.ParseTemplate(model, row.Get<DataModelTemplate, string>(x => x.Template));
  184. if (string.IsNullOrWhiteSpace(attachmentName))
  185. attachmentName = model.Name;
  186. EmailUtils.CreateEMLFile(attachmentName, data, App.EmployeeEmail, Subject, body, to);
  187. }
  188. public static void DoEmailReport(DataModel model, byte[] data)
  189. {
  190. string attachmentName = DetermineName(model);
  191. EmailUtils.CreateEMLFile(attachmentName, data, App.EmployeeEmail, "Emailing report for " + attachmentName);
  192. }
  193. private static string DetermineName(DataModel model)
  194. {
  195. string title = model.Name;
  196. if (model.HasTable<Requisition>())
  197. {
  198. CoreTable table = model.GetTable<Requisition>();
  199. title = title + " - " + table.Rows.FirstOrDefault().Get<Requisition, string>(x => x.Title);
  200. }
  201. else if (model.HasTable<PurchaseOrder>())
  202. {
  203. title = "Purchase Order ";
  204. CoreTable table = model.GetTable<PurchaseOrder>();
  205. if (table.Rows.Count == 1)
  206. title += table.Rows.FirstOrDefault().Get<PurchaseOrder, string>(x => x.PONumber);
  207. else if (table.Rows.Count > 1)
  208. {
  209. foreach (CoreRow row in table.Rows)
  210. {
  211. title = title + row.Get<PurchaseOrder, string>(x => x.PONumber) + ", ";
  212. }
  213. title = title.Substring(0, title.Length - 2);
  214. }
  215. }
  216. return title;
  217. }
  218. }
  219. }