一、相关概念
QQ邮箱关于三种协议的解释:SMTP/IMAP服务
1.SMTP协议
SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是一种用于发送电子邮件的互联网标准。它在TCP/IP协议族中,通常使用25端口进行通信。SMTP协议允许邮件发送者和接收者之间的邮件传输,并且可以通过中继器或网关实现不同网络之间的邮件传输。SMTP的一个重要特性是它能够跨越网络传输邮件,这被称为“SMTP邮件中继”。
2.POP3协议
POP3 (Post Office Protocol - Version 3)协议用于支持使用电子邮件客户端获取并删除在服务器上的电子邮件。
POP允许电子邮件客户端下载服务器上的邮件,但是你在电子邮件客户端上的操作(如:移动邮件、标记已读等)不会反馈到服务器上的,比如:你通过电子邮件客户端收取了QQ邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,QQ邮箱服务器上的这些邮件是没有同时被移动的。需要特别注意的是,第三方客户端通过POP收取邮件时,也是有可能同步删除服务端邮件。
3.IMAP协议
IMAP(Internet Message Access Protocol,互联网邮件访问协议)是一个应用层协议,用于从本地邮件客户端(如Microsoft Outlook、Outlook Express、Foxmail、Mozilla Thunderbird)访问远程服务器上的邮件。
在IMAP协议上,电子邮件客户端的操作都会反馈到服务器上,你对邮件进行的操作(如:移动邮件、标记已读、删除邮件等)服务器上的邮件也会做相应的动作。也就是说,IMAP 是“双向”的。
4.守护进程
守护进程是后台运行的无终端关联的系统进程,常在启动时启动,提供持续服务,如网络服务、日志记录和定时任务。其特点包括脱离终端、后台运行、持久服务、资源管理和错误处理。创建守护进程涉及重定向文件描述符、创建新会话、改变工作目录等步骤。`ps` 和 `top` 命令用于查看守护进程,前者提供进程快照,后者显示实时资源使用情况。
二、实践
1.telnet登录QQ发送邮件
打开PowerShell,输入下面命令打开telnet
telnet smtp.qq.com 587
如果无法识别telnet,打开控制面板,点击卸载程序,点击左侧的 “启用或关闭 Windows 功能”
找到 “Telnet 客户端”,勾选它,然后点击确定
等待安装完成,重新打开 PowerShell 或 CMD
按照以下步骤发送邮件
telnet smtp.qq.com 587 (qq邮箱说明:http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=369)
Ehlo qq.com (打招呼)
STARTTLS (开启加密)
auth login (输入登陆命令)
//输入邮箱账号(Base64形式)(回车)
//输入邮箱授权码(Base64形式)(回车)
235 Authentication successful(提示登陆成功)
Mail from:XXXX@qq.com (注意冒号后面别有空格)
250 Ok
Rcpt to:XXX@qq.com (注意冒号后面别有空格)
250 Ok
DATA (输入此命令开始写信)
FROM:XXX@qq.com
TO:XXX@qq.com
SUBJECT:
(空一行)
内容
. (“.”结束)
quit
2.守护进程实现
首先登录QQ邮箱,点击左下方账号与安全中心,点击安全设置,点击生成授权码
在代码中需要用到你的qq邮箱地址(账号@qq.com)和授权码的base64形式,可到此处转换:https://base64.us/
进入在linux系统,输入以下命令,创建.c文件
vim smtp_daemon.c
守护进程代码如下(C语言):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>#define SMTP_SERVER "smtp.qq.com"
#define SMTP_PORT 465 // 使用SSL加密端口
#define EMAIL_FROM "你的qq邮箱地址"
#define EMAIL_PASS "邮箱密码或授权码" // 确认这是最新的授权码
#define EMAIL_TO "实际接收邮箱"SSL_CTX* init_ssl() {SSL_library_init();SSL_load_error_strings();OpenSSL_add_all_algorithms();return SSL_CTX_new(SSLv23_client_method());
}void send_email() {SSL_CTX* ctx = init_ssl();int sockfd;struct hostent *server;struct sockaddr_in serv_addr;char buffer[1024];// 创建socket连接sockfd = socket(AF_INET, SOCK_STREAM, 0);server = gethostbyname(SMTP_SERVER);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SMTP_PORT);memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection failed");return;}// SSL握手SSL* ssl = SSL_new(ctx);SSL_set_fd(ssl, sockfd);if (SSL_connect(ssl) <= 0) {ERR_print_errors_fp(stderr);return;}// SMTP协议交互SSL_read(ssl, buffer, sizeof(buffer)); // 读取欢迎消息sprintf(buffer, "EHLO localhost\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));sprintf(buffer, "AUTH LOGIN\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));// 发送base64编码sprintf(buffer, "实际base64编码\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));sprintf(buffer, "实际base64编码\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));// 设置发件人和收件人sprintf(buffer, "MAIL FROM:<%s>\r\n", EMAIL_FROM);SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));sprintf(buffer, "RCPT TO:<%s>\r\n", EMAIL_TO);SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));// 发送邮件内容sprintf(buffer, "DATA\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));time_t now;time(&now);sprintf(buffer, "From: <%s>\r\n""To: <%s>\r\n""Subject: 守护进程状态\r\n""\r\n""守护进程正在运行中....\r\n""当前时间: %s\r\n"".\r\n", EMAIL_FROM, EMAIL_TO, ctime(&now));SSL_write(ssl, buffer, strlen(buffer));SSL_read(ssl, buffer, sizeof(buffer));sprintf(buffer, "QUIT\r\n");SSL_write(ssl, buffer, strlen(buffer));SSL_free(ssl);close(sockfd);SSL_CTX_free(ctx);
}void daemonize() {pid_t pid = fork();if (pid < 0) exit(1);if (pid > 0) exit(0);setsid();chdir("/");umask(0);close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);
}int main() {daemonize();while(1) {send_email();sleep(60);}return 0;
}
其中邮箱地址以及授权码内容替换为你自己的
编译此文件
gcc smtp_daemon.c -o smtp_daemon -lssl -lcrypto
运行守护程序:
./smtp_daemon
运行结果如下图:
停止命令:
pkill -f smtp_daemon
三、总结
本次学习了如何使用telnet登录QQ发送邮件,这一步除了挺多的错,找了一些博客看其中的方法也不行,老是断连。参考文章为Email-FTP-RTSP协议实践研究_rtp邮箱-CSDN博客