我有下一个使用SMTP客户端的示例代码,当我尝试通过使用SSL的邮件发送邮件时,我得到以下内容:
550 SMTP仅在启用SSL或TLS连接时可用。
如何扩展此示例以实现SSL,例如通过gmail等发送电子邮件...我更喜欢套接字编码而没有外部库:
int main()
{
if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
{
printf("Error in WSAStartup(...)\n");
return 1; }
// creating socket
s = socket (AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
{
printf("Error in socket(...)\n");
return 1; }
//get server address
d_addr = gethostbyname ("smtp.mail.ru");
if (d_addr==NULL)
{
printf("Error in gethostbyname(...)\n");
return 1; };
// fill address parameters
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((unsigned long *) d_addr->h_addr);
addr.sin_port = htons (25);
// connecting...
if (SOCKET_ERROR == (connect (s, (sockaddr *) &addr,
sizeof (addr))))
{
printf("Error in connect(...)\n");
return 1; }
// waiting from answer from server
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// sy hello to server
strcpy(text,"HELO smtp.mail.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting approve from server
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// set sender
strcpy(text,"MAIL FROM: sender@mail.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// set receiver
strcpy(text,"RCPT TO: receiver@mtu-net.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// ready to start sending letter
strcpy(text,"DATA\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// from whom letter
strcpy(text,"FROM: sender@mail.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// receiver
strcpy(text,"TO: receiver@mtu-net.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// letter subject
strcpy(text,"SUBJECT: test\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// letter text
strcpy(text,"Hi!\nIt is a message for you\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// telling that we finish
strcpy(text,"\r\n.\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// quit
strcpy(text,"QUIT");
send(s,text,strlen(text),0);
printf("send - %s", text);
// close socket
closesocket(s);
return 0;
}
答案 0 :(得分:2)
服务器告诉您发送了一个SMTP命令,该命令要求套接字连接首先处于安全状态(尽管服务器应该使用回复代码530
代替)。
您正在连接到端口25,该端口通常是未加密的 SMTP端口。 加密 SMTP端口通常为465(隐式SSL)和587(显式TLS)。
您还使用过时的HELO
命令。您应该使用EHLO
命令(请参阅RFC 2821 Section 4.1.1.1)。这将允许服务器向您发送其功能列表(特别是其当前的安全性和身份验证设置)。
在端口25和587上,SMTP通信最初是未加密。您可以连接并立即收到服务器的SMTP问候语,并发送您的初始HELO
/ EHLO
命令。如果EHLO
回复包含STARTTLS
功能(请参阅RFC 3207),您可以发送STARTTLS
命令以启动SSL / TLS握手加密从那一刻开始的通信。 STARTTLS
成功后,发送新的EHLO
命令以获取更新的功能,然后再发送任何后续命令。
在端口465上,SMTP通信始终为加密。您必须在连接到服务器后立即启动SSL / TLS握手,然后才能发送其SMTP问候语并发送初始HELO
/ EHLO
命令。
现在,关于SSL / TLS会话本身,有很多不同的方法可以实现,但不要尝试从头开始实现SSL / TLS!它非常复杂,你会弄错。使用现有的外部API /库,为您完成所有艰苦的工作。要在现有套接字代码之上添加SSL / TLS,您可以使用OpenSSL或Microsoft的Crypto API(特别是其SChannel提供程序),甚至是WinSock' s拥有Secure Socket extensions。或者,您可以将第三方库替换为手动套接字代码,以便为您处理所有SMTP和SSL / TLS逻辑,例如libcurl。
答案 1 :(得分:0)
解决此问题的另一种方法可能是在Scott Gifford的sslclient下运行您的C程序(请参阅http://www.superscript.com/ucspi-ssl/sslclient.html)。 sslclient将生成您的程序,并在您指定的端口上打开与服务器的SSL连接,并将程序的标准输出管道传送到服务器,并将服务器的输出管道输出到您的程序的标准输入。这样做的好处是你可以让sslclient完成所有繁重的工作,只要设置套接字和ssl等,你就可以专注于程序的核心功能。