MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Как отправить отчёт себе на почту в Windows Forms без ввода пароля C#?"
Answer 978363
Как ни странно, это возможно. Просто вместо использования SMTP-сервера нужно взять на себя его работу: определить целевой SMTP-сервер путем запроса MX-записи, подключиться к нему и передать данные. Для этого понадобится два вспомогательных класса:
Для получения MX-записей (взято с https://social.msdn.microsoft.com/Forums/vstudio/en-US/89b21138-596f-4efc-8e86-d440d260c41e/how-to-find-smtp-mail-server-name-and-port?forum=csharpgeneral)
using System; using System.Collections; using System.Text; using System.Runtime.InteropServices; namespace ConsoleTest1 { public static class Mx { [DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)]ref string pszName, QueryTypes wType, QueryOptions options, int aipServers, ref IntPtr ppQueryResults, int pReserved); [DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)] private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType); public static string[] GetMXRecords(string domain) { IntPtr ptr1 = IntPtr.Zero; IntPtr ptr2 = IntPtr.Zero; MXRecord recMx; if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new NotSupportedException(); } ArrayList list1 = new ArrayList(); int num1 = Mx.DnsQuery(ref domain, QueryTypes.DNS_TYPE_MX, QueryOptions.DNS_QUERY_BYPASS_CACHE, 0, ref ptr1, 0); if (num1 != 0) { throw new ApplicationException(num1.ToString()); } for (ptr2 = ptr1; !ptr2.Equals(IntPtr.Zero); ptr2 = recMx.pNext) { recMx = (MXRecord)Marshal.PtrToStructure(ptr2, typeof(MXRecord)); if (recMx.wType == 15) { string text1 = Marshal.PtrToStringAuto(recMx.pNameExchange); list1.Add(text1); } } Mx.DnsRecordListFree(ptr2, 0); return (string[])list1.ToArray(typeof(string)); } private enum QueryOptions { DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1, DNS_QUERY_BYPASS_CACHE = 8, DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000, DNS_QUERY_NO_HOSTS_FILE = 0x40, DNS_QUERY_NO_LOCAL_NAME = 0x20, DNS_QUERY_NO_NETBT = 0x80, DNS_QUERY_NO_RECURSION = 4, DNS_QUERY_NO_WIRE_QUERY = 0x10, DNS_QUERY_RESERVED = -16777216, DNS_QUERY_RETURN_MESSAGE = 0x200, DNS_QUERY_STANDARD = 0, DNS_QUERY_TREAT_AS_FQDN = 0x1000, DNS_QUERY_USE_TCP_ONLY = 2, DNS_QUERY_WIRE_ONLY = 0x100 } private enum QueryTypes { DNS_TYPE_MX = 15 } [StructLayout(LayoutKind.Sequential)] private struct MXRecord { public IntPtr pNext; public string pName; public short wType; public short wDataLength; public int flags; public int dwTtl; public int dwReserved; public IntPtr pNameExchange; public short wPreference; public short Pad; } } }
Для отправки почты по SMTP (слегка модифицированный класс отсюда: http://www.nullskull.com/articles/20030316.asp)
using System; using System.Text; using System.IO; using System.Net.Sockets; using System.Net; using System.Net.NetworkInformation; using System.Web.Mail; namespace SMTP { /// <summary> /// provides methods to send email via smtp direct to mail server /// </summary> public class SmtpDirect { /// <summary> /// Get / Set the name of the SMTP mail server /// </summary> public static string SmtpServer; public static StringBuilder output; private enum SMTPResponse : int { CONNECT_SUCCESS = 220, GENERIC_SUCCESS = 250, DATA_SUCCESS = 354, QUIT_SUCCESS = 221 } public static bool Send(MailMessage message) { output = new StringBuilder(300); IPHostEntry IPhst = Dns.Resolve(SmtpServer); IPEndPoint endPt = new IPEndPoint(IPhst.AddressList[0], 25); Socket s = new Socket(endPt.AddressFamily, SocketType.Stream, ProtocolType.Tcp); s.Connect(endPt); if (!Check_Response(s, SMTPResponse.CONNECT_SUCCESS)) { s.Close(); return false; } Senddata(s, "HELO example.com\r\n"); output.AppendLine("HELO"); if (!Check_Response(s, SMTPResponse.GENERIC_SUCCESS)) { s.Close(); return false; } Senddata(s, string.Format("MAIL From: {0}\r\n", message.From)); output.AppendLine("MAIL From"); if (!Check_Response(s, SMTPResponse.GENERIC_SUCCESS)) { s.Close(); return false; } string _To = message.To; string[] Tos = _To.Split(new char[] { ';' }); foreach (string To in Tos) { Senddata(s, string.Format("RCPT TO: {0}\r\n", To)); output.AppendLine("RCPT TO"); if (!Check_Response(s, SMTPResponse.GENERIC_SUCCESS)) { s.Close(); return false; } } if (message.Cc != null) { Tos = message.Cc.Split(new char[] { ';' }); foreach (string To in Tos) { Senddata(s, string.Format("RCPT TO: {0}\r\n", To)); output.AppendLine("RCPT TO"); if (!Check_Response(s, SMTPResponse.GENERIC_SUCCESS)) { s.Close(); return false; } } } StringBuilder Header = new StringBuilder(); Header.Append("From: " + message.From + "\r\n"); Tos = message.To.Split(new char[] { ';' }); Header.Append("To: "); for (int i = 0; i < Tos.Length; i++) { Header.Append(i > 0 ? "," : ""); Header.Append(Tos[i]); } Header.Append("\r\n"); if (message.Cc != null) { Tos = message.Cc.Split(new char[] { ';' }); Header.Append("Cc: "); for (int i = 0; i < Tos.Length; i++) { Header.Append(i > 0 ? "," : ""); Header.Append(Tos[i]); } Header.Append("\r\n"); } Header.Append("Date: "); Header.Append(DateTime.Now.ToString("ddd, d M y H:m:s z")); Header.Append("\r\n"); Header.Append("Subject: " + message.Subject + "\r\n"); Header.Append("X-Mailer: SMTPDirect v1\r\n"); string MsgBody = message.Body; if (!MsgBody.EndsWith("\r\n")) MsgBody += "\r\n"; if (message.Attachments.Count > 0) { Header.Append("MIME-Version: 1.0\r\n"); Header.Append("Content-Type: multipart/mixed; boundary=unique-boundary-1\r\n"); Header.Append("\r\n"); Header.Append("This is a multi-part message in MIME format.\r\n"); StringBuilder sb = new StringBuilder(); sb.Append("--unique-boundary-1\r\n"); sb.Append("Content-Type: text/plain\r\n"); sb.Append("Content-Transfer-Encoding: 7Bit\r\n"); sb.Append("\r\n"); sb.Append(MsgBody + "\r\n"); sb.Append("\r\n"); foreach (object o in message.Attachments) { MailAttachment a = o as MailAttachment; byte[] binaryData; if (a != null) { FileInfo f = new FileInfo(a.Filename); sb.Append("--unique-boundary-1\r\n"); sb.Append("Content-Type: application/octet-stream; file=" + f.Name + "\r\n"); sb.Append("Content-Transfer-Encoding: base64\r\n"); sb.Append("Content-Dispos" + "ition: attachment; filename=" + f.Name + "\r\n"); sb.Append("\r\n"); FileStream fs = f.OpenRead(); binaryData = new Byte[fs.Length]; long bytesRead = fs.Read(binaryData, 0, (int)fs.Length); fs.Close(); string base64String = System.Convert.ToBase64String(binaryData, 0, binaryData.Length); for (int i = 0; i < base64String.Length; ) { int nextchunk = 100; if (base64String.Length - (i + nextchunk) < 0) nextchunk = base64String.Length - i; sb.Append(base64String.Substring(i, nextchunk)); sb.Append("\r\n"); i += nextchunk; } sb.Append("\r\n"); } } MsgBody = sb.ToString(); } Senddata(s, ("DATA\r\n")); output.AppendLine("DATA"); if (!Check_Response(s, SMTPResponse.DATA_SUCCESS)) { s.Close(); return false; } Header.Append("\r\n"); Header.Append(MsgBody); Header.Append(".\r\n"); Header.Append("\r\n"); Header.Append("\r\n"); Senddata(s, Header.ToString()); if (!Check_Response(s, SMTPResponse.GENERIC_SUCCESS)) { s.Close(); return false; } Senddata(s, "QUIT\r\n"); output.AppendLine("QUIT"); Check_Response(s, SMTPResponse.QUIT_SUCCESS); s.Close(); return true; } private static void Senddata(Socket s, string msg) { byte[] _msg = Encoding.ASCII.GetBytes(msg); s.Send(_msg, 0, _msg.Length, SocketFlags.None); } private static bool Check_Response(Socket s, SMTPResponse response_expected) { string sResponse; int response; byte[] bytes = new byte[1024]; while (s.Available == 0) { System.Threading.Thread.Sleep(100); } s.Receive(bytes, 0, s.Available, SocketFlags.None); sResponse = Encoding.ASCII.GetString(bytes); sResponse = sResponse.Replace("\0", ""); output.Append(sResponse); response = Convert.ToInt32(sResponse.Substring(0, 3)); if (response != (int)response_expected) return false; return true; } } }
Использование:
using System; using System.Collections.Generic; using System.Web; using System.Web.Mail; using SMTP; namespace ConsoleTest1 { class Program { static void Main(string[] args) { string dest = "pupkin@example.com"; string[] elems = dest.Split("@".ToCharArray()); string[] arr = Mx.GetMXRecords(elems[1]); string s = ""; foreach (string x in arr) s += x + Environment.NewLine; Console.WriteLine("MX records:" + Environment.NewLine + s); MailMessage msg = new MailMessage(); msg.To = dest; msg.From = "pupkin@example.com"; msg.Subject = "Hello, world"; msg.Body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; SmtpDirect.SmtpServer = arr[0]; SmtpDirect.Send(msg); Console.WriteLine(SmtpDirect.output.ToString()); Console.ReadKey(); } } }
Недостаток в том, что отправленное таким образом письмо гарантированно попадет в спам, а также рядом с адресом отправителя будет отображаться предупреждение, что он "подделан".
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.