diff --git a/Mailer/Lib/App.cs b/Mailer/Lib/App.cs index 2b36685..1a5670f 100644 --- a/Mailer/Lib/App.cs +++ b/Mailer/Lib/App.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2016-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ @@ -13,7 +13,7 @@ namespace Lib /// /// Properties of application /// - class App + public class App { #region Info /// @@ -27,17 +27,17 @@ class App /// /// Файл записи лога приложения /// - public static string Log = Path.ChangeExtension(App.Exe, string.Format("{0:yyyyMMdd}.log", DateTime.Now)); + public static string Log = Path.ChangeExtension(Exe, string.Format("{0:yyyyMMdd}.log", DateTime.Now)); - static Assembly assembly = Assembly.GetCallingAssembly(); - static AssemblyName assemblyName = assembly.GetName(); - public static readonly string Name = assemblyName.Name; + static readonly Assembly _assembly = Assembly.GetCallingAssembly(); + static readonly AssemblyName _assemblyName = _assembly.GetName(); + public static readonly string Name = _assemblyName.Name; // Major.Minor.Build.Revision /// /// Версия программы /// - public static readonly Version Ver = assemblyName.Version; + public static readonly Version Ver = _assemblyName.Version; /// /// Название и версия программы в виде строки (если есть - с номером построения) /// @@ -45,20 +45,23 @@ class App (Ver.Revision > 0 ? " build " + Ver.Revision.ToString() : string.Empty); //public static readonly string attribute = (attribute == null) ? string.Empty : attribute; - static AssemblyDescriptionAttribute descriptionAttribute = AssemblyDescriptionAttribute.GetCustomAttribute(assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute; + static readonly AssemblyDescriptionAttribute descriptionAttribute = + Attribute.GetCustomAttribute(_assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute; public static readonly string Description = descriptionAttribute.Description; - static AssemblyCompanyAttribute companyAttribute = AssemblyCompanyAttribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute; + static readonly AssemblyCompanyAttribute _companyAttribute = + Attribute.GetCustomAttribute(_assembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute; /// /// Компания разработчика приложения /// - public static readonly string Company = companyAttribute.Company; + public static readonly string Company = _companyAttribute.Company; - static AssemblyCopyrightAttribute copyrightAttribute = AssemblyCopyrightAttribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute; + static readonly AssemblyCopyrightAttribute _copyrightAttribute = + Attribute.GetCustomAttribute(_assembly, typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute; /// /// Авторские права на приложение /// - public static readonly string Copyright = copyrightAttribute.Copyright; + public static readonly string Copyright = _copyrightAttribute.Copyright; #endregion Info #region Paths @@ -151,16 +154,14 @@ public static string ExitMessage(int code, string msg) StringBuilder sb = new StringBuilder(); if (code > 0) { - sb.Append("Exit "); - sb.Append(code); + sb.Append("Exit ").Append(code); } if (msg != null) { - sb.Append(": "); - sb.Append(msg); + sb.Append(": ").Append(msg); } return sb.ToString(); } #endregion Exit } -} \ No newline at end of file +} diff --git a/Mailer/Lib/AppTraceListener.cs b/Mailer/Lib/AppTraceListener.cs index 98e32ca..2085bdf 100644 --- a/Mailer/Lib/AppTraceListener.cs +++ b/Mailer/Lib/AppTraceListener.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2016-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ @@ -9,7 +9,7 @@ namespace Lib { - class AppTraceListener : DefaultTraceListener + public class AppTraceListener : DefaultTraceListener { public static TraceSwitch TraceConsole = new TraceSwitch("TraceConsole", "Trace level for console in config", "Error"); public static TraceSwitch TraceLog = new TraceSwitch("TraceLog", "Trace level for log in config", "Verbose"); @@ -20,7 +20,7 @@ public AppTraceListener() public AppTraceListener(string file) { - base.LogFileName = file; + LogFileName = file; string path = Path.GetDirectoryName(file); if (!Directory.Exists(path)) @@ -31,7 +31,7 @@ public AppTraceListener(string file) public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) { - this.TraceEvent(eventCache, source, eventType, id, string.Format(format, args)); + TraceEvent(eventCache, source, eventType, id, string.Format(format, args)); } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) @@ -39,7 +39,7 @@ public override void TraceEvent(TraceEventCache eventCache, string source, Trace string msg = BuildMessage(eventType, message); //byte[] bytes = Encoding.GetEncoding(1251).GetBytes(sb.ToString().ToCharArray()); - if (string.IsNullOrEmpty(base.LogFileName)) + if (string.IsNullOrEmpty(LogFileName)) { if (TraceConsole.TraceVerbose) { @@ -50,7 +50,7 @@ public override void TraceEvent(TraceEventCache eventCache, string source, Trace { if (TraceLog.TraceVerbose) { - File.AppendAllText(base.LogFileName, msg, Encoding.GetEncoding(1251)); + File.AppendAllText(LogFileName, msg, Encoding.GetEncoding(1251)); } } } @@ -94,4 +94,4 @@ private static string BuildMessage(TraceEventType eventType, string message) return sb.AppendLine(message).ToString(); } } -} \ No newline at end of file +} diff --git a/Mailer/Lib/EMailMessage.cs b/Mailer/Lib/EMailMessage.cs index 3d3256c..9cadcbd 100644 --- a/Mailer/Lib/EMailMessage.cs +++ b/Mailer/Lib/EMailMessage.cs @@ -1,7 +1,9 @@ -// Copyright (c) 2016-2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2016-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ +using Mailer; + using System; using System.Diagnostics; using System.IO; @@ -11,18 +13,13 @@ namespace Lib { - class EmailMessage : MailMessage + public class EmailMessage : MailMessage { - public EmailMessage() - { - } - - public EmailMessage(string recipients, string subject, string body, string[] files, - string mode, string list) + public EmailMessage(string recipients, string subject, string body, string[] files) { - this.From = new MailAddress("noreply", App.Name, Encoding.UTF8); + From = new MailAddress(Parameters.FROM, App.Name, Encoding.UTF8); - this.To.Add(recipients.Replace(';', ',')); + To.Add(recipients.Replace(';', ',')); // this.CC // this.Bcc // this.ReplyToList; @@ -30,16 +27,17 @@ public EmailMessage(string recipients, string subject, string body, string[] fil // this.IsBodyHtml = true; // this.Priority = MailPriority.High; + string mode = Parameters.MODE; if (subject.Length > 0) { int m = mode.IndexOf(subject[0]); if (m > -1) { - this.Subject = SubjBuilder(m, subject); + Subject = SubjBuilder(m, subject); } else { - this.Subject = subject; + Subject = subject; } } @@ -47,20 +45,20 @@ public EmailMessage(string recipients, string subject, string body, string[] fil { if (mode.IndexOf(body[0]) > -1) { + string list = Parameters.LIST; string[] bodyList = body.Split(list.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - body = string.Empty; foreach (string item in bodyList) { int m = mode.IndexOf(item[0]); if (m > -1) { - this.Body += BodyBuilder(m, item); + Body += BodyBuilder(m, item); } } } else { - this.Body = body; + Body = body; } } @@ -71,10 +69,12 @@ public EmailMessage(string recipients, string subject, string body, string[] fil { Attachment attachment = new Attachment(fi.FullName); ContentDisposition disposition = attachment.ContentDisposition; + disposition.CreationDate = fi.CreationTime; disposition.ModificationDate = fi.LastWriteTime; disposition.ReadDate = fi.LastAccessTime; - this.Attachments.Add(attachment); + + Attachments.Add(attachment); } else { @@ -82,6 +82,7 @@ public EmailMessage(string recipients, string subject, string body, string[] fil } } } + static string SubjBuilder(int mode, string item) { int line = -1; // the last line by default @@ -209,6 +210,7 @@ static string GetBodyContent(string file, Encoding enc, int lines) sb.AppendLine(content[i]); } } + FileInfo fi = new FileInfo(file); sb.AppendFormat("---- eof {0}, {1}B, {2} ----", file, fi.Length, fi.LastWriteTime); sb.AppendLine(); diff --git a/Mailer/Lib/EMailSender.cs b/Mailer/Lib/EMailSender.cs index 6a4fb5c..12adf11 100644 --- a/Mailer/Lib/EMailSender.cs +++ b/Mailer/Lib/EMailSender.cs @@ -1,7 +1,9 @@ -// Copyright (c) 2016-2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2016-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ +using Mailer; + using System; using System.ComponentModel; using System.Diagnostics; @@ -11,34 +13,36 @@ namespace Lib { - class EmailSender + public class EmailSender { public string Host; - public int Port = 25; - public bool Ssl = false; + public int Port; + public bool Ssl; public string Username; public string Password; - public int Timeout = 5; + public int Timeout; - public EmailSender(string host, int port, bool ssl, string user, string pass) + public EmailSender() { - Host = string.IsNullOrEmpty(host) ? Gateway.DefaultGateway() : host; - Port = port; - Ssl = ssl; - Username = user; - Password = Lib.Password.Decode(pass); + Host = Parameters.HOST ?? Gateway.DefaultGateway(); + Port = Parameters.PORT; + Ssl = Parameters.SSL; + Username = Parameters.USER; + Password = Lib.Password.Decode(Parameters.PASS); + Timeout = Parameters.TIMEOUT; } public void SendWait(EmailMessage email) { - SmtpClient client = new SmtpClient(Host, Port); - - client.UseDefaultCredentials = false; - client.Credentials = new NetworkCredential(Username, Password); - client.DeliveryMethod = SmtpDeliveryMethod.Network; - client.EnableSsl = Ssl; + SmtpClient client = new SmtpClient(Host, Port) + { + UseDefaultCredentials = false, + Credentials = new NetworkCredential(Username, Password), + DeliveryMethod = SmtpDeliveryMethod.Network, + EnableSsl = Ssl + }; // client.Timeout = Timeout * 1000; // Ignored for Async // The userState can be any object that allows your callback @@ -89,12 +93,13 @@ public void SendWait(EmailMessage email) private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) { // Get the unique identifier for this asynchronous operation. - String token = (string)e.UserState; + string token = (string)e.UserState; if (e.Cancelled) { Trace.TraceWarning("[{0}] Send canceled.", token); } + if (e.Error != null) { Trace.TraceWarning("[{0}] {1}", token, e.Error.ToString()); @@ -105,10 +110,10 @@ private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs } } - class StatusChecker + protected class StatusChecker { private int invokeCount; - private int maxCount; + private readonly int maxCount; public bool Canceled = false; public bool TimedOut = false; @@ -128,8 +133,7 @@ public void CheckStatus(Object stateInfo) if (Console.KeyAvailable) { - ConsoleKeyInfo keyInfo = new ConsoleKeyInfo(); - keyInfo = Console.ReadKey(true); + ConsoleKeyInfo keyInfo = Console.ReadKey(true); if (keyInfo.Key == ConsoleKey.Escape) { // Reset the counter and signal the waiting thread. diff --git a/Mailer/Lib/Gateway.cs b/Mailer/Lib/Gateway.cs index 7f88db5..2d4483e 100644 --- a/Mailer/Lib/Gateway.cs +++ b/Mailer/Lib/Gateway.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2017-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ @@ -38,4 +38,4 @@ public static string DefaultGateway() return null; } } -} \ No newline at end of file +} diff --git a/Mailer/Lib/Password.cs b/Mailer/Lib/Password.cs index 78a77ac..079bb90 100644 --- a/Mailer/Lib/Password.cs +++ b/Mailer/Lib/Password.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017 Dmitrii Evdokimov. All rights reserved. +// Copyright (c) 2016-2021 Dmitrii Evdokimov. All rights reserved. // Licensed under the Apache License, Version 2.0. // Source https://github.com/diev/ @@ -8,7 +8,7 @@ namespace Lib { - class Password + public class Password { /// /// The base encoding for text strings. 0: UTF8, 866: DOS, 1251: Windows, etc. @@ -57,4 +57,4 @@ public static string Encode(string toEncode) return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks); } } -} \ No newline at end of file +} diff --git a/Mailer/Mailer.csproj b/Mailer/Mailer.csproj index 0a4b406..0cba1cf 100644 --- a/Mailer/Mailer.csproj +++ b/Mailer/Mailer.csproj @@ -9,9 +9,10 @@ Properties Mailer Mailer - v3.5 + v4.8 512 - Client + + AnyCPU @@ -22,6 +23,7 @@ DEBUG;TRACE prompt 4 + false AnyCPU @@ -31,6 +33,7 @@ TRACE prompt 4 + false @@ -48,6 +51,9 @@ + + + + +{% include favicon.html %} diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 941c7ee..b870bcc 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -1,166 +1,16 @@ - -{% if page.url == "/" or page.url == "/index.html" or page.url == "/en.html" %} - {% assign home = true %} -{% endif %} -{% if page.url contains "/about" %} - {% assign about = true %} -{% endif %} -{% if page.url contains "/en.html" or page.url contains "-en.html" %} - {% assign en = true %} - {% assign lang = "en" %} - {% assign langx = "-en" %} - {% assign author = "Dmitrii Evdokimov" %} -{% else %} - {% assign ru = true %} - {% assign lang = "ru" %} - {% assign langx = "" %} - {% assign author = "Дмитрий Евдокимов" %} -{% endif %} - - - - - {{ site.title | default: site.github.repository_name }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- {% if site.github.is_user_page %} - - {{ content }} - - {% elsif site.github.is_project_page %} -
-

{{ site.title | default: site.github.repository_name }}

-

{{ site.description | default: site.github.project_tagline }}

-
- Project by {{ author }} - Hosted on GitHub -
- - {{ content }} - - {% if home %} -

Downloads

-
- - - {% if en %} - - - - {% else %} - - - - {% endif %} - - - -
Release NotesDownloadDateРелизы и инфоСкачатьДата
- - - {% endif %} - {% endif %} -
- -
- {% if site.google_analytics %} - - - {% endif %} - - +{% include head.html %} +{% include body.html %} +
+
+

{{ site.title | default: site.github.repository_name }}

+

{{ site.description | default: site.github.project_tagline }}

+
+{{ site.locales[lang].maintained }} {{ site.locales[lang].name }} +{{ site.locales[lang].hosted }} GitHub +
+
+
+{{ content }} +
+{% include download.html %} +{% include footer.html %} diff --git a/docs/index.md b/docs/index.md index 8812025..a53cd8a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ # Mailer -[![Build status](https://ci.appveyor.com/api/projects/status/ukoqyhda8b706p02/branch/master?svg=true)](https://ci.appveyor.com/project/diev/mailer/branch/master) -[![GitHub Release](https://img.shields.io/github/release/diev/Mailer.svg)](https://github.com/diev/Mailer/releases/latest) +[![Build status]][appveyor] +[![GitHub Release]][releases] A simple console email sender to send reports from batch files without any configs. @@ -11,9 +11,7 @@ any configs. Just compile with your target .NET (2.0, 3.5, 4.0+) on your Windows by its bundled C# compiler: -``` -C:\Windows\Microsoft.NET\Framework\...\scs.exe /out:Mailer.exe /recurse:*.cs -``` + C:\Windows\Microsoft.NET\Framework\...\scs.exe /out:Mailer.exe /recurse:*.cs Use enclosed simple *make.cmd* with preset paths for these .NET. Of course you can use MSBuild itself. @@ -22,24 +20,21 @@ Of course you can use MSBuild itself. Run without arguments (or with '?' in any place) to get help. -``` -Mailer.exe ? -``` + Mailer.exe ? Use at least one argument in such order: -``` -Mailer to subject body attach -``` + Mailer to subject body attach If instead *to* is '-', it will be used the parameter from source (see *Parameters.cs* below). You can write a few recipients separated by ',' (or ';', they will be properly replaced). If *subject* or *body* starts with: -* '-' take content from a file in *DOS 866* -* '=' take content from a file in *Windows 1251* -* '\*' take content from a file in *UTF-8* + + * '-' take content from a file in *DOS 866* + * '=' take content from a file in *Windows 1251* + * '\*' take content from a file in *UTF-8* Additionally after *subject* ':' you can specify a number of line in that file (from top or bottom, if negative). Default is 1 (the first line from @@ -57,65 +52,100 @@ If no arguments or there is '?' somewhere, it will be shown this Usage text. ## Examples -``` -Mailer admin@bank.ru Test -Mailer admin@bank.ru,b.admin@bank.ru,c.admin@bank.ru Test Body-text -Mailer - "Test subject" "Long body text with spaces." -Mailer - "Test DOS file" -filename.txt -Mailer - "Test Win file" =filename.txt -Mailer - "Test UTF file" *filename.txt -Mailer - "Test include" "-Body from DOS 866.txt" -Mailer - "*Subject from UTF-8.txt" "-Body from DOS 866.txt" -Mailer - "Top 10 lines" -c:\filename.txt:10 -Mailer - "Last 5 lines" -c:\filename.txt:-5 -Mailer - report.txt "" report.txt -Mailer - -report.txt:2 "Date in subj, file attached." report.txt -Mailer - =error.log:-1 "Last error in subj!" -Mailer - Files "3 attachments." file1.txt,file2.txt,file3.txt -Mailer - "Just files" "" "Report 2016.xlsm, My Doc.docx" -``` + Mailer admin@bank.ru Test + Mailer admin@bank.ru,b.admin@bank.ru,c.admin@bank.ru Test Body-text + Mailer - "Test subject" "Long body text with spaces." + Mailer - "Test DOS file" -filename.txt + Mailer - "Test Win file" =filename.txt + Mailer - "Test UTF file" *filename.txt + Mailer - "Test include" "-Body from DOS 866.txt" + Mailer - "*Subject from UTF-8.txt" "-Body from DOS 866.txt" + Mailer - "Top 10 lines" -c:\filename.txt:10 + Mailer - "Last 5 lines" -c:\filename.txt:-5 + Mailer - report.txt "" report.txt + Mailer - -report.txt:2 "Date in subj, file attached." report.txt + Mailer - =error.log:-1 "Last error in subj!" + Mailer - Files "3 attachments." file1.txt,file2.txt,file3.txt + Mailer - "Just files" "" "Report 2016.xlsm, My Doc.docx" ## Exit codes for ERRORLEVEL (They still can be changed during the further development.) -* 0 - Normal -* 1 - Email sending was canceled -* 2 - Shown Usage -* 3 - Wrong argument -* 4 - File not found + * 0 - Normal + * 1 - Email sending was canceled + * 2 - Shown Usage + * 3 - Wrong argument + * 4 - File not found ## Parameters.cs ```cs -// The email server's IP or DNS host name (if empty: gateway). -const string HOST = "192.168.0.1"; - -// The TCP port of SMTP. Default is 25. -const int PORT = 25; - -// Use the secured connection. -const bool SSL = false; - -// A username to login into the email server. -const string USER = "sender@bank.ru"; - -// A password encoded in Base64 to login into the email server. -// Do not store any passwords as a plain text! -const string PASS = "c2VuZGVy"; + /// + /// The email server's IP or DNS host name (if empty: gateway). + /// + public const string HOST = ""; + + /// + /// The TCP port of SMTP. Default is 25. + /// + public const int PORT = 25; + + /// + /// Use the secured connection. + /// + public const bool SSL = true; + + /// + /// The timeout in ms. + /// + public const int TIMEOUT = 60000; + + /// + /// The sender's name. + /// + public const string NAME = "Sender"; + + /// + /// The sender's email. + /// + public const string FROM = "noreply@bank.ru"; + + /// + /// A login to the SMTP server. + /// + public const string USER = "sender@bank.ru"; + + /// + /// A password encoded in Base64. Do not store any passwords as a plain text! + /// + public const string PASS = "********"; + + /// + /// Email(s) by default. Maybe separated by ',' signs. + /// + public const string TO = "admin@bank.ru"; + + /// + /// An array of chars to be list separators. + /// + public const string LIST = ",;"; + + /// + /// An array of signatures to read files in the proper encoding: -DOS 866 (0), =Windows 1251 (1), *UTF8 (2). + /// + public const string MODE = "-=*"; // DOS 866, Windows 1251, UTF8 +``` -// Emails of recipients by default. Maybe separated by ',' or ';' signs. -const string TO = "admin@bank.ru"; +## License -// An array of chars to be list separators for attached filenames. -const string LIST = ",;"; +Licensed under the [Apache License, Version 2.0]. -// An array of signatures to read files in the proper encoding: -// -DOS 866 (0), =Windows 1251 (1), *UTF8 (2). -const string MODE = "-=*"; // DOS 866, Windows 1251, UTF8 -``` +[Mailer]: https://diev.github.io/Mailer/ +[Apache License, Version 2.0]: http://www.apache.org/licenses/LICENSE-2.0 "LICENSE" -## License +[appveyor]: https://ci.appveyor.com/project/diev/mailer/branch/master +[releases]: https://github.com/diev/Mailer/releases/latest -Licensed under the [Apache License, -Version 2.0](http://www.apache.org/licenses/LICENSE-2.0 "LICENSE"). +[Build status]: https://ci.appveyor.com/api/projects/status/ukoqyhda8b706p02/branch/master?svg=true +[GitHub Release]: https://img.shields.io/github/release/diev/Mailer.svg