zoukankan      html  css  js  c++  java
  • 使用java语言基于SMTP协议手写邮件客户端

    使用java语言基于SMTP协议手写邮件客户端

    1. 说明

    电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用)。

    电子邮件系统由以下几个部分组成:

    • 用户代理
    • 邮件服务器
    • 邮件传输协议

    总所周知,目前市面上流行的电子邮箱有qq邮箱,163邮箱等,我们可以去申请一个qq邮箱或者163邮箱,原因是因为腾讯和网易提供了邮件服务器。

    同时我们也知道我们不仅仅可以通过qq邮箱的官方客户端收发邮件,而且可以通过其他客户端登入qq邮箱,比如说网易邮箱大师等。这说明邮件服务商提供了邮件服务器,但是用户代理却不局限与该厂商,而用户代理是通过邮件传输协议与邮件服务器进行通信的,也就是说我们只要理解了邮件传输协议,了解一门网络编程语言,就可以动手实现我们自己的邮件客户端了。

    那么我们开始实现吧;

    2. SMTP协议

    SMTP的全称是Simple Mail Transfer Protocol,简单邮件传输协议。顾名思义,这个协议十分的简单,通过对该协议的RFC文档的阅读,我们可以掌握该协议的基本内容,了解从用户代理与邮件服务器的通信规则。

    3 准备工作

    1. 阅读SMTP协议的RFC文档
    2. 搭Maven环境
    3. 编写代码

    4. SMTP协议精要

    RFC文档当然是英文的,本来非常害怕,但是发现他的内容其实很少,所以边看文档边查词典读了两遍(千万别怕),下面是主要内容介绍。

    SMTP协议分为标准SMTP协议和扩展SMTP协议,标准SMTP协议是1982年在RFC821 文档中定义的,而扩展SMTP协议是1995年在RFC1869 文档中定义的。扩展SMTP协议在标准 SMTP协议基础上的改动非常小,主要增加了邮件安全方面的认证功能,现在我们说的SMTP协议基本上都是扩展SMTP协议。

    • introduction介绍:

      主要介绍了SMTP扩展协议为消息传输代理提供了一个稳定的高效的基础(也就是说SMTP协议可以用来实现消息传输代理客户端,也急速邮件客户端)。然后说明了扩展的内容。

    • SMTP扩展协议的框架

      SMTP传输的是邮件对象,邮件对象包括封面和内容

      • 封面包括发件人的地址,多个收件人的地址和交付模式,使用一系列的协议单元发送。
      • 内容包括头部和主题两个部分,使用SMTP数据协议单元发送,头部包括一系列键值对,头部总是使用ASCII编码
    • SMTP协议包含得多指令,但是只需要用到以下指令就可以完成简单的邮件发送

      • ehlo <domain>

        如 ehlo zeng

        与SMTP协议建立连接后需要发送的第一条命令。

      • auth para

        设置验证方式,如auth login

      • mail from: <发送者邮箱>

        设置发送者邮箱,如mail from:<xxxx@qq.com>

      • rcpt to:<收件者邮箱>

        设置收件者邮箱,如rcpt to:<xxxx@qq.com>

      • data

        表示将要发送邮件的内容,这个命令后面的发送都是邮件内容

      • quit

        结束邮件发送

    所有命令末尾都是回车换行

    5. 源码

    import com.sun.xml.internal.messaging.saaj.util.Base64;
    import lombok.Data;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    /**
     * @author zeng
     */
    public class MyEmailClient {
        public static void main(String[] args) throws IOException {
            //敏感信息。。
            Token token=new Token("",25,"","");
            Socket socket=null;
            PrintWriter printWriter=null;
            BufferedReader br=null;
            
            try {
                //1. 连接smtp邮箱服务器
                socket=new Socket(token.getAddress(),token.getPort());
                printWriter=new PrintWriter(socket.getOutputStream(),true);
                br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //2. 第一条命令 ehlo
                printWriter.println("ehlo zeng");
                System.out.println(br.readLine());
                //3. 发送,auth
                printWriter.println("auth login");
                System.out.println(br.readLine());
                //4. 用户名和密码
                printWriter.println(token.getUserName());
                printWriter.println(token.getPassWord());
                //会有一大串信息返回,如果最后返回235 Authentication successful则成功
                String temp=null;
                while ((temp=br.readLine())!=null){
                    System.out.println(temp);
                    if ("235 Authentication successful".equals(temp)){
                        break;
                    }
                }
                System.out.println("认证成功");
    
                //设置发件人和收件人,敏感信息
                String sentUser="";
                String recUser="";
                printWriter.println("mail from:<"+sentUser+">");
                System.out.println(br.readLine());
                printWriter.println("rcpt to:<"+recUser+">");
                System.out.println(br.readLine());
    
                //设置data
                printWriter.println("data");
                System.out.println(br.readLine());
    
                //设置邮件主题
                printWriter.println("subject:test");
                printWriter.println("from:"+sentUser);
                printWriter.println("to:"+recUser);
                //设置邮件格式
                printWriter.println("Content-Type: text/plain;charset="utf8"");
                printWriter.println();
                //邮件正文
                printWriter.println("来自java手写smtp邮件客户端");
                printWriter.println(".");
                printWriter.print("");
                System.out.println(br.readLine());
    
                //退出
                printWriter.println("rset");
                System.out.println(br.readLine());
                printWriter.println("quit");
                System.out.println(br.readLine());
    
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //释放连接
                socket.close();
                printWriter.close();
                br.close();
            }
        }
    }
    @Data
    class Token{
        String address;
        Integer port;
        String userName;
        String passWord;
    
       Token(String address, Integer port, String userName, String passWord) {
            this.address = address;
            this.port = port;
            this.userName = new String(Base64.encode(userName.getBytes()));
            this.passWord = new String(Base64.encode(passWord.getBytes()));
        }
    }
    
    

    6.题外话

    之所以写这个的原因是自己把计网考完后阅读了《计算机网络 自顶向下方法》这本书,该书应用层协议的课后习题就有一个实现邮件客户端,当时看到这个题目的时候,感觉不可思议,因为之前课堂上学计网的时候都是一些理论的知识,真没想过自己动手写代码。之前在写Spring代码的时候也用过mail相关的类,所以自己也决定通过读RFC文档去实现一个自己的邮件客户端,以帮助我发现更多的乐趣。

  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/zeng-xian-hui/p/11221519.html
Copyright © 2011-2022 走看看