using System; using System.Collections.Generic; using System.IO; using System.Net.Mail; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace BanTur.Core.Utility { public class MailSender { private readonly string _host; private readonly int _smtpPort; private readonly string _user; private readonly string _pass; private readonly string _senderName; public MailSender(string host, int smtpPort, string user, string pass, string senderName) { _host = host; _smtpPort = smtpPort; _user = user; _pass = pass; _senderName = senderName; } public MailSender() : this( DbAccess.Config.SendMailHost, DbAccess.Config.SendMailPort, DbAccess.Config.SendMailUser, DbAccess.Config.SendMailPass, "BanTur") { } public void SendMailAndForget(string subject, string body = "") { Task.Factory.StartNew(() => SendMail(subject, body)); } public void SendMail(string subject, string body = "") { SendMail(DbAccess.Config.SendMailTarget, subject, DbAccess.Config.SendMailTargetName, body); } public void SendMail(string to, string subject, string toName, string body) { var cl = new TcpClient(); cl.SmtpConnect(_host, _smtpPort); cl.SmtpLogin(_user, _pass); cl.SmtpSendMail(_user, to, subject, body, _senderName, toName); cl.SmtpQuit(); } } internal static class MailExtensions { //-- internal func -- private static void SmtpCheckStatus(this TcpClient client, int status) { var line = client.ReadAsciiLine(); if (line.StartsWith(status + " ") == false) throw new SmtpException(line); } //-- public func -- public static void SmtpConnect(this TcpClient client, string host, int port) { client.Connect(host, port); client.SmtpCheckStatus(220); } public static void SmtpLogin(this TcpClient client, string user, string pass) { client.WriteLine("AUTH LOGIN"); client.SmtpCheckStatus(334); client.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(user))); client.SmtpCheckStatus(334); client.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(pass))); client.SmtpCheckStatus(235); } public static void SmtpSendMail(this TcpClient client, string from, string to, string subject, string body = "", string senderName = "", string toName = "") { var bodyB64 = Convert.ToBase64String( Encoding.UTF8.GetBytes(body + Environment.NewLine + "Mail generate by LibSharpMail") , Base64FormattingOptions.InsertLineBreaks); client.WriteLine("MAIL FROM: <{0}>", from); client.SmtpCheckStatus(250); client.WriteLine("RCPT TO: <{0}>", to); client.SmtpCheckStatus(250); client.WriteLine("DATA"); client.SmtpCheckStatus(354); client.WriteLine("Subject: {0}", subject.SubjectEncoding()); client.WriteLine("From: \"{1}\" <{0}>", from, senderName.SubjectEncoding()); client.WriteLine("TO: \"{1}\" <{0}>", to, toName); client.WriteLine("MIME-Version: 1.0"); client.WriteLine("Content-Type: multipart/mixed; boundary=frontier"); client.WriteLine(""); client.WriteLine("This is a message with multiple parts in MIME format."); client.WriteLine("--frontier"); client.WriteLine("Content-Type: text/plain; charset=utf-8"); client.WriteLine("Content-Transfer-Encoding: base64"); client.WriteLine(""); client.WriteLine(bodyB64); client.WriteLine("--frontier--"); client.WriteLine("."); client.SmtpCheckStatus(250); } public static void SmtpQuit(this TcpClient client) { client.WriteLine("QUIT"); client.SmtpCheckStatus(221); client.Close(); } //////////////////////// private const byte Cr = (byte)'\r'; private const byte Lf = (byte)'\n'; private static readonly byte[] CrLf = { Cr, Lf }; public static string SubjectEncoding(this string subject, Encoding encoding = null) { var enc = encoding ?? Encoding.UTF8; return $"=?{enc.BodyName}?B?{Convert.ToBase64String(enc.GetBytes(subject))}?="; } public static void WriteBytes(this Stream s, byte[] bytes) { s.Write(bytes, 0, bytes.Length); } public static void WriteCrlf(this Stream s) { s.WriteBytes(CrLf); } public static void WriteLine(this TcpClient client, string s) { client.WriteLine("{0}", s); } public static void WriteLine(this TcpClient client, string fmt, params object[] args) { var s = client.GetStream(); s.WriteBytes(Encoding.ASCII.GetBytes(String.Format(fmt, args))); s.WriteCrlf(); } public static byte[] ReadBinLine(this TcpClient client) { var s = client.GetStream(); var ms = new MemoryStream(); var len = 0; do { var b = s.ReadByte(); if (b < 0) continue; ms.WriteByte((byte)b); len++; if (len < 2) continue; var msbuf = ms.GetBuffer(); if (msbuf[len - 2] == Cr && msbuf[len - 1] == Lf) break; } while (true); var buf = new byte[len - 2]; Array.Copy(ms.GetBuffer(), 0, buf, 0, len - 2); return buf; } public static string ReadAsciiLine(this TcpClient client) { return Encoding.ASCII.GetString(client.ReadBinLine()); } public static string[] ReadAsciiLinesUntilDot(this TcpClient client) { var ret = new List(); do { var line = client.ReadAsciiLine(); if (line.Trim() == ".") break; ret.Add(line); } while (true); return ret.ToArray(); } public static byte[][] ReadBinLineUntilDot(this TcpClient client) { var ret = new List(); do { var line = client.ReadBinLine(); if (line.Length > 0 && line[0] == (byte)'.') break; ret.Add(line); } while (true); return ret.ToArray(); } } }