`
stephen830
  • 浏览: 3010139 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

晒下以前根据RFC821SMTP协议写的发Email方法

    博客分类:
  • java
阅读更多
★★★ 本篇为原创,需要引用转载的朋友请注明:《 http://stephen830.iteye.com/blog/255099 》 谢谢支持! ★★★

这是老早以前根据RFC821协议[SIMPLE MAIL TRANSFER PROTOCOL]写的用于发email的方法。附件部分有点问题。有兴趣的朋友可以参考下。

关于RFC821协议[SIMPLE MAIL TRANSFER PROTOCOL]的具体内容可以访问: http://james.apache.org/server/rfclist/smtp/rfc0821.txt

下面是MailTool.java的具体内容:

/*
 * Created on 2005-6-1
 * Author stephen
 * Email zhoujianqiang AT gmail DOT com
 * CopyRight(C)2005-2008 , All rights reserved.
 */
package com.soft4j.utility;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 电子邮件Email的处理类.
 * 
 * @author stephen
 * @version 1.0.0
 */
public final class MailTool {

    private final static String END_FLAG = "\r\n";//SMTP/ESMTP命令结束标记
    private final static String EMAIL_ATTACH_SIGN = "=====att";//邮件附件的表示符号

    private String smtpServer = null;//邮件发送服务器域名
    private int smtpPort = 25;//邮件发送端口
    private Socket clientMailSocket;//邮件连接socket
    private InputStream inData;//接收数据    
    private OutputStream outData;//发送数据
    private String mailUserName = null;//邮件账户
    private String mailUserPass = null;//邮件账户的密码
    private String mailTo = null;//邮件发送目标
    private String mailFrom = null;//邮件发送人
    private String mailSubject = null;//邮件主题
    private String mailBody = null;//邮件正文   
    private String mailShowTo = null;//邮件内容抬头部分-邮件发送目标
    private String mailShowFrom = null;//邮件内容抬头部分-邮件发送人
    private String[] mailAttachFile = null;//邮件附件对应的本地文件名(包含绝对路径)
    private int mailType = 1;//邮件类型:1=文本邮件,2=HTML邮件
    
    /**
     * @return Returns the mailAttachFile.
     */
    public String[] getMailAttachFile() {
        return mailAttachFile;
    }
    /**
     * @param mailAttachFile The mailAttachFile to set.
     */
    public void setMailAttachFile(String[] mailAttachFile) {
        this.mailAttachFile = mailAttachFile;
    }
    /**
     * @return Returns the mailShowFrom.
     */
    public String getMailShowFrom() {
        return mailShowFrom;
    }
    /**
     * @param mailShowFrom The mailShowFrom to set.
     */
    public void setMailShowFrom(String mailShowFrom) {
        this.mailShowFrom = mailShowFrom;
    }
    /**
     * @return Returns the mailShowTo.
     */
    public String getMailShowTo() {
        return mailShowTo;
    }
    /**
     * @param mailShowTo The mailShowTo to set.
     */
    public void setMailShowTo(String mailShowTo) {
        this.mailShowTo = mailShowTo;
    }

    
    /**
     * @return Returns the mailBody.
     */
    public String getMailBody() {
        return mailBody;
    }
    /**
     * @param mailBody The mailBody to set.
     */
    public void setMailBody(String mailBody) {
        this.mailBody = mailBody;
    }
    /**
     * @return Returns the mailFrom.
     */
    public String getMailFrom() {
        return mailFrom;
    }
    /**
     * @param mailFrom The mailFrom to set.
     */
    public void setMailFrom(String mailFrom) {
        this.mailFrom = mailFrom;
    }
    /**
     * @return Returns the mailSubject.
     */
    public String getMailSubject() {
        return mailSubject;
    }
    /**
     * @param mailSubject The mailSubject to set.
     */
    public void setMailSubject(String mailSubject) {
        this.mailSubject = mailSubject;
    }
    /**
     * @return Returns the mailTo.
     */
    public String getMailTo() {
        return mailTo;
    }
    /**
     * @param mailTo The mailTo to set.
     */
    public void setMailTo(String mailTo) {
        this.mailTo = mailTo;
    }
    /**
     * @return Returns the mailUserName.
     */
    public String getMailUserName() {
        return mailUserName;
    }
    /**
     * @param mailUserName The mailUserName to set.
     */
    public void setMailUserName(String mailUserName) {
        this.mailUserName = mailUserName;
    }
    /**
     * @return Returns the mailUserPass.
     */
    public String getMailUserPass() {
        return mailUserPass;
    }
    /**
     * @param mailUserPass The mailUserPass to set.
     */
    public void setMailUserPass(String mailUserPass) {
        this.mailUserPass = mailUserPass;
    }
    
    

    /**
     * 获取属性-
     * @return Returns the mailType.
     */
    public int getMailType() {
        return mailType;
    }
    /**
     * 设置属性-
     * @param mailType The mailType to set.
     */
    public void setMailType(int mailType) {
        this.mailType = mailType;
    }
    /**
     * 构造器方法.
     * @param _smtpServer smtp服务器名(ip地址)
     * @param _smtpPort smtp端口号.
     */
    public MailTool(String smtpServer,int smtpPort){
        this.smtpServer = smtpServer;
        this.smtpPort = smtpPort;
    }
    
    
    /**
     * 与smtp邮件服务器建立连结.
     * @return
     */
    public boolean createConnection(){
        try {
            freeAll();
            clientMailSocket = new Socket(smtpServer, smtpPort);
            inData = clientMailSocket.getInputStream();
            outData = clientMailSocket.getOutputStream();
            fetchCMDResult();//当首次连接服务器后有返回值,必须取走该返回值,否则后面命令的返回值无法判断
        } catch (IOException e) {
            System.out.println("Can't create the connection with " + smtpServer + "on port " + smtpPort + ".", Log.STD_ERR);
            return false;
        }
        return true;
    }
    
    /**
     * 
     * @param in
     * @return
     */
    public static String response(InputStream in){
        byte[] buffer = new byte[1024];
        StringBuffer inData = new StringBuffer();
        int n = 0;
        try {
                n = in.read(buffer);
                inData.append(new String(buffer, 0, n));
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        return inData.toString();

    }
    
    public static void send(String s, OutputStream out){
        byte[] buffer = s.getBytes();
        try {
            out.write(buffer);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public String fetchCMDResult(){
        return response(inData);
    }
    
    public boolean sendCmd(String _cmd) {
        if (_cmd != null) {
            send(_cmd,outData);
        }
        return true;
    }
    
    /**
     * 发送邮件
     * 服务器为ESMTP时候采用本方法
     * @return true=send ok,false=send failed.
     */
    public boolean sendMail() {
        
        //打开与邮件服务器的连接
        if(!createConnection()){
            return false;
        }
        StringBuffer theContent = new StringBuffer();

        //EHLO
        theContent.append("EHLO ");
        theContent.append(smtpServer);
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("250")==-1) return false;
        //AUTH LOGIN
        theContent.delete(0,theContent.length());
        theContent.append("AUTH LOGIN");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        try { Thread.sleep(5000); } catch (Exception e) {}
        if(fetchCMDResult().indexOf("334")==-1) return false;
        //用户名
        theContent.delete(0,theContent.length());
        theContent.append(Base64Encode(this.mailUserName));
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("334")==-1) return false;
        //密码
        theContent.delete(0,theContent.length());
        theContent.append(Base64Encode(this.mailUserPass));
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        try { Thread.sleep(5000); } catch (Exception e) {}
        if(fetchCMDResult().indexOf("235")==-1) return false;
        //邮件发送者
        theContent.delete(0,theContent.length());
        theContent.append("MAIL FROM:");
        theContent.append("<");
        theContent.append(this.mailFrom);
        theContent.append(">");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("250")==-1) return false;
        //邮件发送目标地址
        theContent.delete(0,theContent.length());
        theContent.append("RCPT TO:");
        theContent.append("<");
        theContent.append(this.mailTo);
        theContent.append(">");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("250")==-1) return false;
        
        //邮件内容-开始
        theContent.delete(0,theContent.length());
        theContent.append("DATA");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("354")==-1) return false;
        //邮件内容-邮件抬头部分
        theContent.delete(0,theContent.length());
        theContent.append("From:");
        theContent.append(this.mailShowFrom);
        theContent.append(END_FLAG);
        theContent.append("To:");
        theContent.append(this.mailShowTo);
        theContent.append(END_FLAG);
        theContent.append("Subject:");
        theContent.append(this.mailSubject);
        theContent.append(END_FLAG);
        theContent.append("Mime-Version: 1.0");
        theContent.append(END_FLAG);
        

        theContent.append("Content-Type: multipart/mixed;Boundary=\"");//设置附件表示符
        theContent.append(EMAIL_ATTACH_SIGN);
        theContent.append("\"");
        theContent.append(END_FLAG);//在正文内容前必须有2个END_FLAG标记
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());

        //邮件内容-正文部分
        theContent.delete(0,theContent.length());
        theContent.append("--");
        theContent.append(EMAIL_ATTACH_SIGN);
        theContent.append(END_FLAG);
        switch(mailType){
            case 2:theContent.append("Content-type:text/html;");break;
            default:theContent.append("Content-type:text/plain;");break;
        }
        theContent.append(END_FLAG);
        theContent.append("Content-Transfer-Encoding: base64");
        theContent.append(END_FLAG);
        theContent.append(END_FLAG);
        theContent.append(Base64Encode(this.mailBody));
        theContent.append(END_FLAG);
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        
        //邮件内容-附件部分
        mailAttachFile = null;
        if(mailAttachFile!=null && mailAttachFile.length>0){
            for(int i=0;i<this.mailAttachFile.length;i++){
                //发送附件抬头
                theContent.delete(0,theContent.length());
                theContent.append("--");
                theContent.append(EMAIL_ATTACH_SIGN);
                theContent.append(i);
                theContent.append(END_FLAG);
                theContent.append("Content-Type:image/gif;name=\"aaa.gif\"");
                theContent.append(END_FLAG);
                theContent.append("Content-Transfer-Encoding:base64");
                theContent.append(END_FLAG);
                theContent.append("Content-Disposition:attachment;name=\"aaa.gif\"");
                theContent.append(END_FLAG);
                theContent.append(END_FLAG);
                sendCmd(theContent.toString());
                
                //发送附件内容
                sendBase64Data(new StringBuffer(Base64Encode(readFile(mailAttachFile[i]))));
                
                //发送附件结束
                /*
                theContent = new StringBuffer();
                theContent.append(END_FLAG);
                theContent.append("--");
                theContent.append(EMAIL_ATTACH_SIGN);
                theContent.append(i);
                theContent.append("--");
                theContent.append(END_FLAG);
                sendCmd(theContent.toString());
                */
            }
            
        }
        
        
        //发送附件结束
        theContent.delete(0,theContent.length());
        theContent.append(END_FLAG);
        theContent.append(END_FLAG);
        theContent.append("--");
        theContent.append(EMAIL_ATTACH_SIGN);
        theContent.append("--");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        
        //邮件内容-结束标记
        theContent.delete(0,theContent.length());
        theContent.append(END_FLAG);
        theContent.append(".");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        if(fetchCMDResult().indexOf("250")==-1) return false;
        
        //退出断开服务器连接
        theContent.delete(0,theContent.length());
        theContent.append("QUIT");
        theContent.append(END_FLAG);
        sendCmd(theContent.toString());
        fetchCMDResult();
        
        //邮件发送成功后释放资源
        freeAll();
        theContent = null;
        
        return true;//邮件发送成功
    }
    
    /**
     * 发送经过Base64编码后的数据
     * @param src
     */
    public void sendBase64Data(StringBuffer srcData){
        int LEN_CMD_DATA = 76;
        int startIndex = 0;
        int totalLength = 0;
        if(srcData!=null && srcData.length()>0){
            totalLength = srcData.length();
            while(true){
                if(startIndex+LEN_CMD_DATA<totalLength){
                    sendCmd(srcData.substring(startIndex,startIndex+LEN_CMD_DATA));
                    sendCmd(END_FLAG);
                }else{
                    sendCmd(srcData.substring(startIndex,totalLength));
                    sendCmd(END_FLAG);
                    break;
                }
                startIndex = startIndex+LEN_CMD_DATA;
            }
        }
    }
    
    /**
     * 释放所有资源
     *
     */
    public void freeAll(){
        if(inData!=null){
            try {
                inData.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            inData = null;
        }
        
        if(outData!=null){
            try {
                outData.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            outData = null;
        }   
        
        if(clientMailSocket!=null){
            try {
                clientMailSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            clientMailSocket = null;
        }
        
    }
    
    
    /**
     * 读取文件内容
     * @param fileName
     * @return
     */
    public String readFile(String fileName){
        byte[] fileBuffer = new byte[1024];
        int realSize = 0;
        StringBuffer readContent = new StringBuffer();
        try {
            InputStream inFile = new FileInputStream(new File(fileName));
            while(true){
                realSize = inFile.read(fileBuffer);
                if(-1==realSize) break;
                readContent.append(new String(fileBuffer,0,realSize));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return readContent.toString();
    }

    /**
     * Base64编码函数
     * 将指定的字符串编码为Base64格式的字符串
     * @param src
     * @return
     */
    public static String Base64Encode(String src) {
        if (src == null || src.length() == 0)
            return "";
        String EncodingTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        byte[] Buffer = src.getBytes();
        int ReadNow, i, res;
        char[] WriteBuf = new char[4];
        char[] Buf = new char[3];
        String EncodedStr = "";
        int ReadIndex = 0;
        int Len = Buffer.length;
        boolean isEnd;
        int BytesWritten = 0;
        ReadNow = 0;
        do {
            isEnd = false;
            for (i = 0; i < 3; i++) {
                if (ReadIndex >= Len) {
                    isEnd = true;
                    ReadNow = i;
                    break;
                }
                Buf[i] = (char) (((byte) Buffer[ReadIndex]) & 0x00FF);
                ReadIndex = ReadIndex + 1;
            }
            if (isEnd)
                break;
            WriteBuf[0] = EncodingTable.charAt((Buf[0] >> 2) & 0x003F);
            WriteBuf[1] = EncodingTable
                    .charAt(((Buf[0] & 3) << 4 | (Buf[1] >> 4)) & 0x003F);
            WriteBuf[2] = EncodingTable
                    .charAt(((Buf[1] & 15) << 2 | (Buf[2] >> 6)) & 0x003F);
            WriteBuf[3] = EncodingTable.charAt((Buf[2] & 63) & 0x003F);
            for (i = 0; i < 4; i++)
                EncodedStr = EncodedStr + WriteBuf[i];
            BytesWritten = BytesWritten + 4;
            if ((BytesWritten % 76) == 0) {
                EncodedStr = EncodedStr + "";
            }
        } while (ReadNow != 3);
        if (ReadNow < 3) {
            switch (ReadNow) {
            case 1:
                WriteBuf[0] = EncodingTable.charAt((Buf[0] >> 2) & 0x003F);
                WriteBuf[1] = EncodingTable
                        .charAt(((Buf[0] & 3) << 4) & 0x003F);
                WriteBuf[2] = '=';
                WriteBuf[3] = '=';
                for (i = 0; i < 4; i++)
                    EncodedStr = EncodedStr + WriteBuf[i];
                break;
            case 2:
                WriteBuf[0] = EncodingTable.charAt((Buf[0] >> 2) & 0x003F);
                WriteBuf[1] = EncodingTable
                        .charAt(((Buf[0] & 3) << 4 | (Buf[1] >> 4)) & 0x003F);
                WriteBuf[2] = EncodingTable
                        .charAt(((Buf[1] & 15) << 2) & 0x003F);
                WriteBuf[3] = '=';
                for (i = 0; i < 4; i++)
                    EncodedStr = EncodedStr + WriteBuf[i];
                break;
            default:
                break;
            }
        }
        return (EncodedStr);
    }
    
    /**
     * 测试用的main方法.
     * @param args main方法的参数.
     */
    public static void main(String[] args) {
        
        MailTool foxMail = new MailTool("mail.xxx.com",25);//smtp服务器地址
        foxMail.setMailUserName("username@xxx.com");//mail.xxx.com的一个email用户
        foxMail.setMailUserPass("password");//username@xxx.com账户的密码
        foxMail.setMailTo("username@yyy.com");//发送目标email地址
        foxMail.setMailFrom("username@xxx.com");
        foxMail.setMailShowTo("你好");
        foxMail.setMailShowFrom("哈哈");
        foxMail.setMailSubject("hello用中文主题");
        foxMail.setMailBody("welcome for you. 中文呀.aaa \r\n再来一行");

        if(foxMail.sendMail()){
            System.out.println("OK.");
        }else{
            System.out.println("False.");
        }
        foxMail = null;
        
    }
}




当初写这个方法,主要是为了学习下RFC821协议,比较简单,没有作很深入的研究.






















1
0
分享到:
评论

相关推荐

    rfc821-c.tar.gz_RFC821_TAR?IN TOZU mail

    在这些文件中,我们可能会看到对RFC821协议的各种操作,如解析SMTP命令、验证邮件头、处理邮件正文、管理邮件队列等。 通过解压并阅读这些源代码,我们可以深入了解SMTP服务器的工作原理,学习如何用C语言实现网络...

    计算机网络实验二.docx

    实验“Windows环境下用smtp实现Email客户端”旨在让学生深入理解和掌握网络编程,特别是SMTP协议的工作原理。 实验背景: SMTP协议在RFC 821 [Postel 1982]中被规范,定义了两个MTA(报文传送代理)之间的通信方式...

    精彩编程与编程技巧-SMTP协议简介 (Simple Mail Transfer Protocol)...

    SMTP协议基于RFC 821标准进行定义,并且后续有多个修订版本,如RFC 2821等。SMTP使用TCP端口25进行通信,并且通过一系列的命令和响应码来实现邮件的发送过程。SMTP的基本操作流程包括连接建立、邮件头信息交换、邮件...

    Email 邮件协议编程实例 源码 in vc

    使用SMTP协议,你需要构造符合SMTP命令格式的消息,包括发件人、收件人、主题和邮件正文。在VC中,这通常涉及创建TCP套接字,发送命令,然后发送邮件数据。例如,使用MFC,你可以创建CInternetSession对象,然后使用...

    Internet Email协议开发指南

    作者Kevin Johnson将分散在多种RFC(Request for Comments)和软件包中的信息整合,全面阐述了Internet电子邮件的关键技术和实现方法。 书中首先介绍了电子邮件的基本概念,涵盖了电子邮件的格式,包括MIME...

    vc++ STMP协议发送email 源代码

    在这个场景中,"vc++ STMP协议发送email 源代码"指的是使用VC++编程语言实现的一个程序,能够通过SMTP协议与邮件服务器交互,从而发送电子邮件。 首先,我们要理解SMTP的工作原理。SMTP主要用于邮件服务器之间的...

    IMAP4邮件接收协议rfc3501

    RFC 3501还提及IMAP4rev1不包括发送邮件的机制,发送邮件的功能由其他邮件传输协议如SMTP(简单邮件传输协议,RFC2821)来完成。 IMAP4rev1协议在安全性方面,虽然没有明确定义,但在实际应用中常与其他安全协议如...

    SMTP客户端

    总的来说,实现一个SMTP客户端涉及网络编程、SMTP协议理解和邮件格式规范等多个层面。通过WinSocket库,开发者可以构建自己的邮件发送程序,实现邮件的有效验证和发送。在实际项目中,还可以考虑集成其他功能,如...

    Visual C++之Email协议编程

    首先,理解SMTP协议是发送邮件的核心。SMTP用于从邮件客户端向邮件服务器发送邮件。在Visual C++中,可以使用如Winsock库来实现SMTP通信。这个库提供了网络编程的基本接口,允许开发者编写TCP/IP应用程序,包括邮件...

    SMTP.rar_vc smtp

    3. **SMTP命令**:SMTP协议定义了一系列的命令,如HELO/EHLO(向服务器打招呼)、MAIL FROM(指定发件人)、RCPT TO(指定收件人)、DATA(发送邮件内容)和QUIT(结束会话)。源代码中会实现这些命令的发送和响应的...

    rfc 2183

    Content-Disposition头字段是在HTTP协议、MIME(多用途互联网邮件扩展)以及SMTP(简单邮件传输协议)等场景下用来指示资源的预期处理方式,尤其是在处理附件时。例如,它可以帮助区分一个文件是应该被显示在浏览器...

    分析网络应用层Email协议

    总结来说,通过DOS下的telnet工具,我们可以直接与邮件服务器进行低级别交互,这有助于我们更好地理解Email协议的工作原理,包括SMTP、POP3和IMAP4。这样的实践不仅能够提升技术知识,也是对网络安全和数据传输机制...

    Go-mailck-golang库用于实现基于smtp的email校验

    SMTP是互联网上标准的邮件传输协议,用于发送和接收电子邮件。`mailck`库提供了一个简洁且高效的解决方案,帮助开发者确保输入的电子邮件地址是有效的,并且能够通过SMTP服务器进行通信。 SMTP验证的过程通常包括...

    email客户端源码

    总的来说,"email客户端源码"的项目涵盖了C++编程、网络编程、SMTP协议理解和应用,以及可能的加密和身份验证技术。通过深入研究这些源码,开发者可以学习到如何在实际项目中实现电子邮件的发送和接收功能,进一步...

    java Email工具类

    MIME(Multipurpose Internet Mail Extensions)协议是扩展RFC822标准以支持多种类型的数据,比如文本、图像、音频和视频等。 在JavaMailUtils类中,可以看到关键方法`sendEmail()`,这个方法用于发送邮件。首先,...

    email_demo.rar

    1. **SMTP协议**:SMTP是一种用于发送电子邮件的标准网络协议。它允许用户通过邮件服务器向其他互联网用户发送邮件。SMTP工作流程通常包括身份验证、邮件构建、传输和确认。在`email_demo`中,C++类可能会包含发送...

    java发送Email_群发email.rar

    这是一个强大的库,它提供了丰富的接口和类,可以处理SMTP(简单邮件传输协议)、POP3(邮局协议)和IMAP(因特网消息访问协议)等邮件协议。以下是一些关键的知识点: 1. **JavaMail API**: 这是Java发送邮件的...

    计算机Email服务器的配置与应用(“邮件”相关文档)共51张.pptx

    本资源摘要信息是关于计算机Email服务器的配置与应用的详细知识点,涵盖了电子邮件的基本原理、MUA、MTA、SMTP、POP3、IMAP协议之间的关系、Sendmail和Qmail的配置方法等内容。 一、电子邮件的基本原理 电子邮件(e...

    Email发送程序源码。

    总结来说,要理解并使用这个“Email发送程序源码”,你需要熟悉SMTP协议、邮件服务器认证机制、MIME邮件构造以及邮件头部的创建。通过阅读和学习这个源码,你可以掌握如何在实际项目中实现邮件发送功能,这对于任何...

    C#邮件收发,收件有点乱码

    System.Net.Mail命名空间提供了SmtpClient和MailMessage类来处理SMTP协议的邮件发送。在创建MailMessage对象时,我们可以设置Subject(主题)和Body(正文)的编码,例如使用Unicode(UTF-8)编码,以确保支持大多数...

Global site tag (gtag.js) - Google Analytics