0xAA55 发表于 2015-12-31 06:31:19

【Java】java轻量级电子邮件类smtpmail(不是JavaMail),支持附件

用法:
1、初始化。smtpmail sm=new smtpmail();
sm.SetServer(服务器地址,端口号,用户名,密码,发件人,收件人);2、发送简单的纯文本邮件:sm.SendTextMail(是否使用SSL加密,如果不使用SSL加密是不是服务器必须支持TLS加密才继续发送,标题,内容);3、发送复杂的邮件:try
{
      sm.StartSendMail(是否使用SSL加密,如果不使用SSL加密是不是服务器必须支持TLS加密才继续发送,标题,有没有附件);
      sm.SendPlainText(纯文本内容);
      sm.SendHTML(HTML格式的内容);
      sm.SendAttachment(附件的MIME类型,附件名,文件名,附件内容字节数组);
      sm.FinishSendMail();
}
catch(IOException e)
{
      e.printStackTrace();
}4、调试:int 最后收到的状态码 = sm.GetLastStatus();
String 最后发送的内容 = sm.GetLastSend();
String 最后收到的内容 = sm.GetLastRecv();
String 最后发送的内容和最后收到的内容 = sm.GetLastSendRecv();5、杂项

[*]使用SSL加密的时候,你需要在smtpmail类的文件夹下村一个SMTP服务器的数字签名文件。否则握手失败——抛出HandShakeException。
举个例子,我要使用QQ的smtp服务器,获取它数字签名的方法是用浏览器进入https://mail.qq.com然后在浏览器的“锁”标识找到证书,并将其复制到文件。


然后在弹出的窗口里找到“详细信息”选项卡,点开,点“复制到文件”按钮。

然后跟着向导走一遍就行了。向导的话详细的自己看着办吧。
[*]不使用SSL加密或者STARTTLS加密的电子邮箱服务器基本上已经不存在了。
[*]这个类只需要实体化一遍就可以随便使用。只需要在发送前保证SetServer填的那些内容都对就行了。


源码:import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.UUID;
import java.util.Base64;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/**
* Created by 0xAA55 on 2015/12/7.
* Author: 0xAA55
* Website: http://www.0xaa55.com
*/

public class smtpmail
{
        final private String nl="\r\n";//换行符
        final private String nlnl=nl+nl;//换行符
        private String m_Sep;//分隔符
        //服务器
        private String m_ServerAddr;
        private int m_ServerPort;
        //用户账号
        private String m_Username;
        private String m_Password;
        //发送者和接收者
        private String m_MailFrom;
        private String m_RcptTo;
        //状态
        private String m_LastSend;
        private String m_LastRecv;
        private int m_LastStatus;
        //读写器
        private Socket m_s;
        private BufferedReader m_br;
        private PrintStream m_ps;

        //=========================================================================
        //方法:ConnectToServer
        //描述:连接到服务器
        private void ConnectToServer()throws IOException
        {
                m_s=new Socket(m_ServerAddr,m_ServerPort);
                m_br=new BufferedReader(new InputStreamReader(m_s.getInputStream()));
                m_ps=new PrintStream(m_s.getOutputStream());
        }

        //=========================================================================
        //方法:SSLConnectToServer
        //描述:使用SSL加密连接到服务器
        private void SSLConnectToServer()throws IOException
        {
                SSLSocket ss=(SSLSocket)((SSLSocketFactory)SSLSocketFactory.getDefault())
                                .createSocket(m_ServerAddr,m_ServerPort);
                ss.setEnableSessionCreation(true);
                ss.setUseClientMode(true);
                ss.startHandshake();
                m_s=ss;
                m_br=new BufferedReader(new InputStreamReader(ss.getInputStream()));
                m_ps=new PrintStream(ss.getOutputStream());
        }

        //=========================================================================
        //方法:TurnToSSL
        //描述:转为SSL安全连接
        private void TurnToSSL()throws IOException
        {
                SSLSocket ss=(SSLSocket)((SSLSocketFactory)SSLSocketFactory.getDefault())
                                .createSocket(m_s,m_ServerAddr,m_ServerPort,true);
                ss.setEnableSessionCreation(true);
                ss.setUseClientMode(true);
                //STARTTLS没有握手
                //ss.startHandshake();
                m_s=ss;
                m_br=new BufferedReader(new InputStreamReader(ss.getInputStream()));
                m_ps=new PrintStream(ss.getOutputStream());
        }

        //=========================================================================
        //方法:SendSMTPData
        //描述:发送SMTP数据
        private void SendSMTPData(String command)throws IOException
        {
                m_ps.print(command);
                m_LastSend=command;
                // Log.d("smtpmail","Send:"+m_LastSend.replace(nl,""));
                System.out.println("Send:"+m_LastSend);
        }

        //=========================================================================
        //方法:RecvSMTPData
        //描述:获取一条服务器返回的内容,取得状态码
        private int RecvSMTPData()throws IOException
        {
                //从服务器读取一行返回的内容
                m_LastRecv=m_br.readLine();
                // Log.d("smtpmail","Recv:"+m_LastRecv);
                System.out.println("Recv:"+m_LastRecv);

                if(m_LastRecv == null || m_LastRecv.length() == 0)//如果没有取得内容,则抛出错误
                        throw new IOException("RecvSMTPData: no status code.");

                //分析字符串,从前面取得状态码
                char[]ch=m_LastRecv.toCharArray();
                int i;
                m_LastStatus=0;
                for(i=0;i<m_LastRecv.length();i++)
                {
                        //读取数字直到遇到别的字符
                        if(ch>='0'&&ch<='9')
                                m_LastStatus=m_LastStatus*10+ch-'0';
                        else
                                break;
                }
                if(i==0)//如果没有取得内容,则抛出错误
                        throw new IOException("RecvSMTPData: no status code.");
                return m_LastStatus;
        }

        //=========================================================================
        //方法:StartTls
        //描述:发送STARTTLS,然后获取服务器的支持情况
        private boolean StartTls()throws IOException
        {
                //发送STARTTLS
                SendSMTPData("STARTTLS"+nl);

                //接收到220时表示STARTTLS成功,而接收到的值超过300的就表示失败
                do
                {
                        if(RecvSMTPData()==220)
                                return true;
                }while(m_LastStatus<300);
                return false;
        }

        //=========================================================================
        //方法:AuthLogin
        //描述:验证用户名和密码
        private boolean AuthLogin()throws IOException
        {
                //发送AUTH LOGIN,然后接收服务器返回
                SendSMTPData("AUTH LOGIN "+nl);

                //略过所有的2xx返回内容
                do
                        RecvSMTPData();
                while(m_LastStatus<300);

                //得到3xx状态后,发送账号密码
                if(m_LastStatus<400)
                {
                        //一次性完成账号和密码的发送
                        SendSMTPData(Base64.getEncoder().encodeToString(m_Username.getBytes())+nl+
                                               Base64.getEncoder().encodeToString(m_Password.getBytes())+nl);
                }
                else
                        return false;//服务器并没有要求输入用户名和密码(或者,530,必须先STARTTLS)

                //发送完账号和密码,等服务器返回结果
                for(;;)
                {
                        RecvSMTPData();//接收内容
                        if(m_LastStatus<300)return true;//验证成功
                        if(m_LastStatus>=400)return false;//其它情况
                }
        }

        //=========================================================================
        //方法:SetFromTo
        //描述:设置发件人和收件人。要求之前服务器返回的数据都已完成读取
        private boolean SetFromTo()throws IOException
        {
                SendSMTPData("MAIL FROM:<"+m_MailFrom+">"+nl);
                //250 OK
                //501 mail from address must be same as authorization user
                if(RecvSMTPData()>=300)return false;

                SendSMTPData("RCPT TO:<"+m_RcptTo+">"+nl);
                //250 OK
                //550 Mailbox not found or access denied
                if(RecvSMTPData()>=300)return false;
                return true;
        }

        //=========================================================================
        //方法:Quit
        //描述:告知服务器关闭连接,同时自己也关闭连接
        private void Quit()
        {
                try
                {
                        SendSMTPData("QUIT"+nl);
                        m_s.close();
                }catch(IOException e)
                {
                        e.printStackTrace();
                }
        }

        //=========================================================================
        //公开方法

        //=========================================================================
        //方法:构造
        //描述:初始化类
        public smtpmail()
        {
                m_LastSend="";
                m_LastRecv="";
                m_LastStatus=0;
        }

        //=========================================================================
        //方法:SetServer
        //描述:设置服务器
        void SetServer(String addr,int port,String user,String pswd,String from,String rcpt)
        {
                m_ServerAddr=addr;
                m_ServerPort=port;
                m_Username=user;
                m_Password=pswd;
                m_MailFrom=from;
                m_RcptTo=rcpt;
        }

        //=========================================================================
        //方法:StartSendMail
        //描述:开始发送邮件
        boolean StartSendMail(boolean SSL,boolean MustUseTls,String Subject,boolean HaveAttachment)throws IOException
        {
                boolean UseTls=false;

                if(SSL)
                        SSLConnectToServer();
                else
                        ConnectToServer();

                //Hello
                SendSMTPData("EHLO "+m_ServerAddr+nl);
                if(RecvSMTPData()!=220)
                {
                        Quit();
                        return false;
                }
                if(!SSL)//如果不是SSL加密,就尝试进行STARTTLS握手
                {
                        if(StartTls())
                        {
                                UseTls=true;//成功表示支持使用TLS加密
                                TurnToSSL();
                                SendSMTPData("EHLO "+m_ServerAddr+nl);
                        }
                        else
                        {
                                if(m_LastStatus == 454)//服务器不支持STARTTLS
                                {
                                        if(MustUseTls)
                                        {
                                                Quit();
                                                return false;//而用户却需要使用STARTTLS
                                        }
                                }
                                else//StartTls返回的其它信息,视为错误
                                {
                                        Quit();
                                        return false;
                                }
                        }
                }

                //验证用户名和密码
                //这之前服务器可能会发回很多的我们不需要的内容,通过这个可以把它刷掉
                if(!AuthLogin())
                {
                        Quit();
                        return false;
                }

                //设置发件人和收件人
                if(!SetFromTo())
                {
                        Quit();
                        return false;
                }

                SendSMTPData("DATA"+nl);
                //354 Enter mail, end with "." on a line by itself
                do
                {
                        if(RecvSMTPData()>=400) return false;
                }
                while(m_LastStatus<300);

                m_Sep="_Part_"+UUID.randomUUID().toString();

                SendSMTPData("From:<"+m_MailFrom+">"+nl+
                                       "To:<"+m_RcptTo+">"+nl+
                                       "Subject: =?UTF-8?B?"+
                                       Base64.getEncoder().encodeToString(Subject.getBytes("UTF-8"))+"?="+nl+
                                       "MIME-Version: 1.0"+nl+
                                       "Content-Type: multipart/"+(HaveAttachment?"mixed;":"alternative;")+" boundary=\""+m_Sep+"\""+nlnl);

                return true;
        }

        //=========================================================================
        //方法:SendPlainText
        //描述:发送纯文本
        void SendPlainText(String Text)throws IOException
        {
                SendSMTPData("--"+m_Sep+nl+
                                       "Content-Type:text/plain; charset=utf-8"+nl+
                                       "Content-transfer-encoding: Base64"+nl+nl+
                                       Base64.getEncoder().encodeToString(Text.getBytes("UTF-8"))+nlnl);
        }

        //=========================================================================
        //方法:SendHTML
        //描述:发送HTML格式的内容
        void SendHTML(String TextHTML)throws IOException
        {
                SendSMTPData("--"+m_Sep+nl+
                                       "Content-Type:text/html; charset=utf-8"+nl+
                                       "Content-transfer-encoding: Base64"+nl+nl+
                                       Base64.getEncoder().encodeToString(TextHTML.getBytes("UTF-8"))+nlnl);
        }

        //=========================================================================
        //方法:SendAttachment
        //描述:发送附件
        void SendAttachment(String MIMEType,String name,String filename,byte[] data)throws IOException
        {
                SendSMTPData("--"+m_Sep+nl+
                                       "Content-Type: "+MIMEType+"; name=\"=?UTF-8?B?"+
                                       Base64.getEncoder().encodeToString(name.getBytes("UTF-8"))+"?=\""+nl+
                                       "Content-Transfer-Encoding: Base64"+nl+
                                       "Content-Disposition: attachment; filename=\"=?UTF-8?B?"+
                                       Base64.getEncoder().encodeToString(filename.getBytes("UTF-8"))+"?=\""+nl+nl+
                                       Base64.getEncoder().encodeToString(data)+nlnl);
        }

        //=========================================================================
        //方法:FinishSendMail
        //描述:结束邮件的发送
        boolean FinishSendMail()throws IOException
        {
                SendSMTPData("--"+m_Sep+"--"+nl+"."+nl);

                //250 2.0.0 tB8BJfTa093352 Message accepted for delivery
                if(RecvSMTPData()>=300)
                {
                        Quit();
                        return false;
                }
                Quit();
                return true;
        }

        //=========================================================================
        //方法:SendTextMail
        //描述:发送纯文本邮件
        boolean SendTextMail(boolean usessl,boolean MustUseTls,String Subject,String Content)
        {
                try
                {
                        if(!StartSendMail(usessl,true,Subject,false))
                                return false;
                        SendPlainText(Content);
                        return FinishSendMail();
                }
                catch(IOException e)
                {
                        e.printStackTrace();
                        return false;
                }
        }

        //=========================================================================
        //方法:Get
        int GetLastStatus()
        {
                return m_LastStatus;
        }
        String GetLastSend()
        {
                return m_LastSend;
        }
        String GetLastRecv()
        {
                return m_LastRecv;
        }
        String GetLastSendRecv()
        {
                return "Last send:"+m_LastSend+"\nLast recv:"+m_LastRecv;
        }
}SRC & BIN:

相关链接:
http://www.0xaa55.com/thread-1650-1-1.html

潘少 发表于 2020-12-4 10:27:51

感谢分享。。。
页: [1]
查看完整版本: 【Java】java轻量级电子邮件类smtpmail(不是JavaMail),支持附件