紧接着上节的介绍,本篇主要以C#的Client socket为基础详细地解析SMTP的发送全部过程,整个代码实现分为3个函数:
1> InitializeSocket,此函数主要是负责初始化Socket,以及连接服务器。
2>SmtpProcessSample,此函数解析一次完整的SMTP会话全过程。
3>UninitializeSocket ,此函数主要是负责关闭socket连接。
由于本文的目标是为了示范SMTP的简约实现,因此错误处理以及SMTP协议交互中的错误码判断以及分支流程均未完成,重点放在整个流程代码的实现,具体的错误处理请读者自己根据前文以及本文的内容以及RFC5321的流程自己实现。
static void Main(string[] args)
{
InitializeSocket();
SmtpProcessSample();
UninitializeSocket();
}
private void InitializeSocket()
{
m_tcpClient = newTcpClient(AddressFamily.InterNetwork);
try
{
m_tcpClient.Connect("smtp.163.com", 25);
System.Diagnostics.Debug.WriteLine("Connetced...");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
m_tcpClient = null;
}
}
private void UninitializeSocket()
{
if (m_tcpClient != null)
{
m_tcpClient.Close();
}
}
private void SmtpProcessSample()
{
string from = "username@163.com";
string to = "dest@xx.com";
string subject = "test subject";
string msg = "aaaaaaaa";
SendCommandLine("EHLO hostname");
PrintResponseLine();
SendCommandLine("AUTH LOGIN");
PrintResponseLine();
// user name/password applying
string nameInBase64 = Convert.ToBase64String(Encoding.ASCII.GetBytes("username"));
string pwdInBase64 = Convert.ToBase64String(Encoding.ASCII.GetBytes("password"));
SendCommandLine(nameInBase64);
PrintResponseLine();
SendCommandLine(pwdInBase64);
PrintResponseLine();
PrintResponseLine();
SendCommandLine("MAIL FROM:<" + from + ">");
PrintResponseLine();
SendCommandLine("RCPT TO:<" + to + ">");
PrintResponseLine();
SendCommandLine("DATA");
PrintResponseLine();
string body = this.GetEmailBodyInformation(from, to, subject, msg);
SendCommandLine(body);
PrintResponseLine();
SendCommandLine("QUIT");
PrintResponseLine();
}
private void SendCommandLine(string commandLine)
{
NetworkStream ns = this.m_tcpClient.GetStream();
string email = commandLine + "\r\n";
byte[] emailBytes = Encoding.ASCII.GetBytes(email);
ns.Write(emailBytes, 0, emailBytes.Length);
System.Diagnostics.Debug.WriteLine(email);
}
privatevoid PrintResponseLine()
{
NetworkStream ns = this.m_tcpClient.GetStream();
byte [] byteBuffer = newbyte[1024];
int read_size = ns.Read(byteBuffer, 0, 1024);
string email = Encoding.ASCII.GetString(byteBuffer, 0, read_size);
System.Diagnostics.Debug.WriteLine(email);
}
private string GetEmailBodyInformation(string from, string to, string subject, string message)
{
StringBuilder msg = newStringBuilder();
msg.Append("MIME-Version: 1.0\r\n");
msg.Append("From: <" + from + ">\r\n");
msg.Append("To: " + to + "\r\n");
msg.Append("Subject: " + subject + "\r\n");
msg.Append("Date: " + DateTime.Now.ToString("F") + "\r\n");
msg.Append("Content-Type: text/plain; ");
msg.Append("charset=\"us-ascii\"\r\n");
msg.Append("Content-Transfer-Encoding: 7bit\r\n");
msg.Append("\r\n");
msg.Append(message + "\r\n\r\n");
msg.Append("\r\n.\r\n");
return msg.ToString();
}
最后的GetEmailBodyInformation函数非常详细地演示了MIME的编码全过程。