Často ani my programátoři nevíme, že komunikace server klient se odehrává často v textovém režimu a ani se příliš neliší od běžné řeči - naše počítače, tedy programy na nich běžící, si mezi sebou povídají pomocí klíčových slov a dohodnutých kódu. Ovšem jako programátoři jsme od této komunikace většinou odděleni a netušíme tak, co probíhá pod pokličkou objektů v našem kódu - možná není špatné si to čas od času připomenout.
Pracuji teď na jednom POC (to je zkratka pro anglické proof of concept - prostě testuji proveditelnost jedné myšlenky v jejich podstatných bodech) a musím zde přímo komunikovat s SMTP serverem.
Pracuji teď na jednom POC (to je zkratka pro anglické proof of concept - prostě testuji proveditelnost jedné myšlenky v jejich podstatných bodech) a musím zde přímo komunikovat s SMTP serverem.
Pokud chcete poslat nějaký email z vaší aplikace, je to vlastně velmi jednoduché a i na tomto blogu lze nalézt pár příkladů, třeba:
nebo
Takový kód pro odeslání pošty vypadá nejčastěji nějak takto:
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress(FromAddress);
foreach (var address in ToAddresses)
mail.To.Add(address);
mail.IsBodyHtml = true;
mail.Body = content;
mail.BodyTransferEncoding = TransferEncoding.Unknown;
mail.Subject = subject + " encoded as " + mail.BodyTransferEncoding.ToString();
using (var client = new SmtpClient(SmtpServer, SmtpPort))
{
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(FromAddress, SmtpPassword);
client.EnableSsl = true;
client.Send(mail);
}
}
{
mail.From = new MailAddress(FromAddress);
foreach (var address in ToAddresses)
mail.To.Add(address);
mail.IsBodyHtml = true;
mail.Body = content;
mail.BodyTransferEncoding = TransferEncoding.Unknown;
mail.Subject = subject + " encoded as " + mail.BodyTransferEncoding.ToString();
using (var client = new SmtpClient(SmtpServer, SmtpPort))
{
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(FromAddress, SmtpPassword);
client.EnableSsl = true;
client.Send(mail);
}
}
Ale lze to řešit i jinak, můžete si se serverem skutečně pokecat. Je dobré si o tom něco přečíst, třeba tady http://cr.yp.to/smtp/mail.html se probírají základni klíčová slova.
V principu něco na server pošleme - příkaz či data a server nám přijetí potvrdí či poskytne další informace. typické příkazy jsou EHLO (Hello...), AUTH LOGIN, MAIL FROM a server nám naopak odpovídá řádkem s kódem a dalšími informacemi. Podle kódu poznáme, jestli je vše v pořádku a můžeme pokračovat v posílání dalších dat apod. Na jeden příkaz můžeme dostat i více řádků, v tom případě obvykle platí, že poslední takový řádek má kód a mezeru, přičemž předchozí mají kód a -. Popisuji to zjednodušeně a je lepší se podívat do specifikací.
V principu něco na server pošleme - příkaz či data a server nám přijetí potvrdí či poskytne další informace. typické příkazy jsou EHLO (Hello...), AUTH LOGIN, MAIL FROM a server nám naopak odpovídá řádkem s kódem a dalšími informacemi. Podle kódu poznáme, jestli je vše v pořádku a můžeme pokračovat v posílání dalších dat apod. Na jeden příkaz můžeme dostat i více řádků, v tom případě obvykle platí, že poslední takový řádek má kód a mezeru, přičemž předchozí mají kód a -. Popisuji to zjednodušeně a je lepší se podívat do specifikací.
A nebo je lepší si to vše pěkně vyzkoušet, tady je prográmek, který místo tříd MailMessage a SmtpClient používá třídu TcpClient a zároven vypisuje i obsah komunikace (aby vám fungoval, musíte použít své jméno a heslo pro Google a v nastavení vašeho Gmail účtu povolit přístup i pro méně bezpečné aplikace):
static void Send()
{
string server = "smtp.gmail.com";
string username = "mstrimpfl@gmail.com";
string password = ".......";
int port = 465;
IPHostEntry ip = Dns.GetHostEntry(server);
IPEndPoint endpoint = new IPEndPoint(ip.AddressList[0], port);
using (var client = new TcpClient())
{
client.Connect(endpoint);
using (var stream = client.GetStream())
{
using (var sslStream = new SslStream(stream)) //transfer data with SSL
{
sslStream.AuthenticateAsClient(server);
using (var writer = new StreamWriter(sslStream) { AutoFlush = true })
using (var reader = new StreamReader(sslStream))
{
writer.WriteLine(string.Format("EHLO {0}", server));
WaitForResponseCode(reader, "250 ");
writer.WriteLine("auth login");
WaitForResponseCode(reader, "334");
writer.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(username)));
writer.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(password)));
WaitForResponseCode(reader, "235 ");
writer.WriteLine(string.Format("MAIL FROM: <{0}>", "test@gmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine(string.Format("RCPT TO: <{0}>", "strimpfl@hotmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine(string.Format("RCPT TO: <{0}>", "mstrimpfl@gmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine("DATA");
WaitForResponseCode(reader, "354");
writer.WriteLine("Subject: ukazka jak na pokec");
writer.WriteLine("From: \"MartinStrimpfl\"");
writer.WriteLine("To: \"Komukoliv\" <everybody@helloworld.com>");
writer.WriteLine("Tohle je jen ukázka");
writer.WriteLine("");
writer.WriteLine("\n");
writer.WriteLine("\n");
writer.WriteLine(".");
WaitForResponseCode(reader, "250");
writer.WriteLine("QUIT");
WaitForResponseCode(reader, "221");
}
}
}
}
Console.ReadLine();
}
static void WaitForResponseCode(StreamReader reader, string code)
{
string response = string.Empty;
do
{
response = reader.ReadLine();
Console.WriteLine(response);
} while (string.IsNullOrEmpty(response) || response.IndexOf(code) < 0);
}
{
string server = "smtp.gmail.com";
string username = "mstrimpfl@gmail.com";
string password = ".......";
int port = 465;
IPHostEntry ip = Dns.GetHostEntry(server);
IPEndPoint endpoint = new IPEndPoint(ip.AddressList[0], port);
using (var client = new TcpClient())
{
client.Connect(endpoint);
using (var stream = client.GetStream())
{
using (var sslStream = new SslStream(stream)) //transfer data with SSL
{
sslStream.AuthenticateAsClient(server);
using (var writer = new StreamWriter(sslStream) { AutoFlush = true })
using (var reader = new StreamReader(sslStream))
{
writer.WriteLine(string.Format("EHLO {0}", server));
WaitForResponseCode(reader, "250 ");
writer.WriteLine("auth login");
WaitForResponseCode(reader, "334");
writer.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(username)));
writer.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(password)));
WaitForResponseCode(reader, "235 ");
writer.WriteLine(string.Format("MAIL FROM: <{0}>", "test@gmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine(string.Format("RCPT TO: <{0}>", "strimpfl@hotmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine(string.Format("RCPT TO: <{0}>", "mstrimpfl@gmail.com"));
WaitForResponseCode(reader, "250 ");
writer.WriteLine("DATA");
WaitForResponseCode(reader, "354");
writer.WriteLine("Subject: ukazka jak na pokec");
writer.WriteLine("From: \"MartinStrimpfl\"");
writer.WriteLine("To: \"Komukoliv\" <everybody@helloworld.com>");
writer.WriteLine("Tohle je jen ukázka");
writer.WriteLine("");
writer.WriteLine("\n");
writer.WriteLine("\n");
writer.WriteLine(".");
WaitForResponseCode(reader, "250");
writer.WriteLine("QUIT");
WaitForResponseCode(reader, "221");
}
}
}
}
Console.ReadLine();
}
static void WaitForResponseCode(StreamReader reader, string code)
{
string response = string.Empty;
do
{
response = reader.ReadLine();
Console.WriteLine(response);
} while (string.IsNullOrEmpty(response) || response.IndexOf(code) < 0);
}
Je to jen výsek plné komunikace, nechtěl jsem příliš řešit, co je ještě senzitivní informace (například moje IP adresa ;-) a co už ne - samozřejmě že při spuštění se objeví všechny informace poslané SMTP zpět.
Žádné komentáře:
Okomentovat