【案例】| C++实现STMP发送邮件

一、STMP基础知识

1、简介
- SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控
	制信件的中转方式;
- SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地,通过SMTP协议所指定的服务器,就可以
	把E-mail寄到收信人的服务器上了,整个过程只要几分钟;而SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中
	转发出的电子邮件;
- MIME规范使得二进制文件能够通过SMTP来传输。目前大多数SMTP软件实现都支持8位MIME扩展,从而使二进制文件的传输变得
	几乎和纯文本一样简单。
2、工作流程

在这里插入图片描述

- 当SMTP客户端有邮件要传送时,与SMTP服务器建立一个双向的传输通道;SMTP客户端负责邮件信息传送到一个或多个SMTP服
	务器,如果失败则给出报告;
- SMTP服务器可能最终目的地,也可能是中间的中继或者网关。SMTP命令由SMTP客户端产生,发送到SMTP服务器。SMTP响应
	由SMTP服务器发送给SMTP客户端,对命令做出回应;
- 邮件传输者可以出现在起始SMTP发送方与最终的SMTP接收方之间建立的连接上,或者出现在通过中间系统的一系列跃点上。一
	旦传输通道建立和初始握手完成,SMTP客户端正常初始化邮件事务。这样的事务包括一系列命令,以定义邮件的发送方和目的
	地,以邮件内容本身的传递;
- 发送者发送 MAIL 命令来指定发送者的邮件,如果接受者接收这个邮件,就回复OK ,接着发送者发送 RCPT命令来指定接收者的
	邮箱,如果被接收同样回复OK,如果不接受则拒绝(不会终止整个通话)。接收者邮箱确定后,发送者用DATA命令指示要发送
	数据,并用一个 .  结束发送。如果数据被接收,会收到OK ,然后用QUIT结束会话;
3、常用指令
【EHLO】:参数为SMTP客户端全称域名;与服务器确认通知其客户端使用的机器名称和地址,标识身份;
	客户端发出后,若服务器支持SMTP服务,则会给出相应的回应;
【AUTH】:使用AUTH LOGIN与服务器进行登录验证;
【MAIL FROM】:发件人信息,若与认证信息不同则被定位为垃圾/恶意邮件;
【RCPT TO】:收件人地址;
【DATA】:邮件基本信息;
【FROM】:邮件基本信息;
【SUBJECT】:邮件标题;
【QUIT】:断开连接;
4、SMTP响应码
211System status, or system help reply
214Help message
220<domain> Service ready
221<domain> Service closing transmission channel
235Authentication successful
250Requested mail action okay, completed
251User not local; will forward to <forward-path>
252Cannot VRFY user, but will accept message and attempt delivery
334AUTH input
354Start mail input; end with <CRLF>.<CRLF>
421<domain> Service not available, closing transmission channel
432A password transition is needed
450Requested mail action not taken: mailbox unavailable
451Requested action aborted: local error in processing
452Requested action not taken: insufficient system storage"
454Temporary authentication failed
500Syntax error, command unrecognized
501Syntax error in parameters or arguments
502Command not implemented
503Bad sequence of commands
504Command parameter not implemented
530Authentication required
534Authentication mechanism is too weak
535Authentication credentials invalid
538Encryption required for requested authentication mechanism
550Requested action not taken: mailbox unavailable
551User not local; please try <forward-path>
552Requested mail action aborted: exceeded storage allocation
553Requested action not taken: mailbox name not allowed
554Transaction failed

二、代码

添加链接描述

#include "smtp.h"
#include <iostream>

namespace Jxiepc {


Smtp::Smtp(int port, std::string domain, std::string user, std::string pwd, 
        std::string t_mail, std::string title, std::string content, std::string type)
    : m_port(port), m_domain(domain), m_user(user), m_password(pwd), m_tmail(t_mail),
    m_title(title), m_content(content), m_type(type) {

    if(init() < 0) {
        perror("init error");
    }
}

Smtp::~Smtp() {
    close(m_sockfd);    
}

int Smtp::init() {
    if(make_connect() == -1) {
        return -1;
    }
    std::string str;

    Recv();
    if(strstr(m_buf, "220") == nullptr) { return -1; } 
    std::cout << "****: " << m_buf << std::endl;

    Send("HELO " + m_user + "\r\n");
    Recv();
    if(strstr(m_buf, "250") == nullptr) { return -1; }


    Send("AUTH LOGIN\r\n");
    Recv();
    if(strstr(m_buf, "334") == nullptr) { return -1; }

    str = m_user.substr(0, m_user.find('@', 0));
    str = enBase64(str.c_str());
    str += "\r\n";
    Send(str);
    Recv();
    if(strstr(m_buf, "334") == nullptr) { return -1; }

    Send(enBase64(m_password.c_str()) + "\r\n");
    Recv();
    if(strstr(m_buf, "235") == nullptr) { return -1; }
    std::cout << "AUTH SUCCESS..." << std::endl;

    Send("MAIL FROM: <" + m_user + ">\r\n");
    Recv();
    if(strstr(m_buf, "250") == nullptr) { return -1; }

    Send("RCPT TO: <" + m_tmail+ ">\r\n");
    Recv();
    if(strstr(m_buf, "250") == nullptr) { return -1; }

    Send("DATA\r\n");
    Recv();

    str = "From: " + m_user + "\r\n";
    str += "To: " + m_tmail + "\r\n";
    str += "Subject: " + m_title + "\r\n";
    str += "Content-Type: multipart/mixed;boundary=qwertyuiop\r\n"; 
    str += "\r\n--qwertyuiop\r\n";

    if(m_type == "html"){
        str += "content-type:text/html;charset=utf-8\r\n"; //html类型
    }else{
        str += "Content-Type: text/plain;charset=utf-8\r\n"; //文本类型
    }

    Send(str);
    str = "\r\n" + m_content + "\r\n";
    str += "\r\n--qwertyuiop--\r\n.\r\n";
    Send(str);
    Recv();
    if(strstr(m_buf, "250") == nullptr) { return -1; }
    std::cout << "send success..." << std::endl;


    Send("QUIT\r\n");

    return 0;
}

int Smtp::make_connect() {
    m_sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    
    hostent *host_info = gethostbyname(m_domain.c_str());
    if(host_info == nullptr){
        perror("gethostbyname error");
        return -1;
    }

    if(host_info->h_addrtype != AF_INET) {
        perror("AF_INET error");
        return -1;
    }
    char buf[128];

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = *((unsigned long*)host_info->h_addr_list[0]);
    addr.sin_port = htons(m_port);
   
    Connect(m_sockfd, (struct sockaddr*)&addr, sizeof(addr));

    return 0;
}

void Smtp::Connect(int fd, const struct sockaddr *sa, socklen_t salen) {
    if(connect(fd, sa, salen)  == -1) {
        perror("connect error");
        exit(-1);
    }
}

int Smtp::Socket(int family, int type, int protocol) {
    int sockfd;
    if((sockfd = socket(family, type, protocol)) == -1) {
        perror("socket error");
        exit(-1);
    }

    return sockfd;
}

ssize_t Smtp::Send(const std::string& str) {
   ssize_t n;
   std::cout << str;
   if((n = send(m_sockfd, str.c_str(), str.length(), 0)) == -1) {
        perror("write error");
        exit(-1);
   }

    return n;
}

ssize_t Smtp::Recv() {
    ssize_t n;
    m_buf[0] = '\0';
    if((n == recv(m_sockfd, m_buf, 0xFFF, 0)) == -1) {
        perror("recv error");
        exit(-1);
    }

    return n;
}

std::string Smtp::enBase64(const std::string& str)   
{
    std::string base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    int str_len = str.length();
    std::string res="";
    for (int strp=0; strp<str_len/3*3; strp+=3)
    {
        res+=base64_table[str[strp]>>2];
        res+=base64_table[(str[strp]&0x3)<<4 | (str[strp+1])>>4];
        res+=base64_table[(str[strp+1]&0xf)<<2 | (str[strp+2])>>6];
        res+=base64_table[(str[strp+2])&0x3f];
    }
    if (str_len%3==1)
    {
        int pos=str_len/3 * 3;
        res += base64_table[str[pos]>>2];
        res += base64_table[(str[pos]&0x3)<<4];
        res += "=";
        res += "=";
    }
    else if (str_len%3==2)
    {
        int pos=str_len/3 * 3;
        res += base64_table[str[pos]>>2];
        res += base64_table[(str[pos]&0x3)<<4 | (str[pos+1])>>4];
        res += base64_table[(str[pos+1]&0xf)<<2];
        res += "=";
    }
    return res;
}

}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用Java实现网易企业邮箱SMTP消息发送,需要使用JavaMail API。以下是一个简单的示例代码: ```java import java.util.Properties; import javax.mail.*; import javax.mail.internet.*; public class EmailSender { public static void main(String[] args) { final String username = "[email protected]"; final String password = "your_email_password"; String fromEmail = "[email protected]"; String toEmail = "[email protected]"; Properties props = new Properties(); props.put("mail.smtp.host", "smtp.qiye.163.com"); props.put("mail.smtp.port", "25"); props.put("mail.smtp.auth", "true"); Session session = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); try { Message message = new MimeMessage(session); message.setFrom(new InternetAddress(fromEmail)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); message.setSubject("Test Email"); message.setText("Hello, this is a test email from Java."); Transport.send(message); System.out.println("Email Sent Successfully"); } catch (MessagingException e) { throw new RuntimeException(e); } } } ``` 在上面的代码中,你需要把`[email protected]`和`your_email_password`替换为你的网易企业邮箱地址和密码,`[email protected]`替换为你要发送邮件的收件人地址。你还需要设置SMTP服务器的主机名和端口号。在这个例子中,我们使用网易企业邮箱的SMTP服务器。 在运行代码之前,请确保你已经包含了JavaMail API。如果你使用Maven,则可以添加以下依赖项: ```xml <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency> ``` 这个例子只是一个简单的入门示例。你可以使用JavaMail API来发送HTML邮件,添加附件,设置抄送和密送等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值