09-10
26

Javamail实现的匿名邮件,模拟邮件服务器发送行为

Sender  ->  Sender's SMTP server  ->  Receiver's SMTP server -> Receiver
  正常流程,SMTP是这样应用的,需要自己的服务器中转。

  其实可以直接Sender - > Receiver's SMTP server ->Receiver.

     Foxmail里面其实也是支持这个的,叫特快信,需要设置一下DNS.

    因为模拟成邮件服务器,给其他邮件服务器发信应该是不需要验证身份的,而且可以乱填发信人的名字,这个就是所谓的匿名信,其实就是垃圾邮件了。但是现在的邮件服务器过滤比较牛了,可以逆向,知道你的发送IP是动态IP,或者逆向发送者的邮箱例如sender@AAA.com, 发现你的IP和DNS找到的AAA.com不匹配估计就知道是乱发,猜测,以下代码很都服务器都发送不了了 :) 但是学习之用。 如果你能使用原始套接字伪装你的IP或者真可以发匿名信了。
  
    对了,邮件服务器之间是通过MX记录来交换邮件的,就是说我是服务器A,要发送邮件到BBB@BBB.com那么我在DNS记录里面查找MX记录,与BBB.com相同的就是我要发送的邮件服务器的IP了。

    MX记录获取可以使用SUN的一个DnsContext的类,或者可以搜索一下,有个老兄自己写Socket直接查DNS记录。
/**************************************************************************************************/

/** 原理介绍,转载**/


什么是DNS?
      域名管理系统DNS(Domain Name System)是域名解析服务器的意思.它在互联网的作用是:把域名转换成为网络可以识别的ip地址.比如:我们上网时输入的www.163.com会自动转换成为202.108.42.72

   什么是A记录?
      A (Address) 记录是用来指定主机名(或域名)对应的IP地址记录。用户可以将该域名下的网站服务器指向到自己的web server上。同时也可以设置您域名的二级域名。

   什么是NS记录?
      NS(Name Server)记录是域名服务器记录,用来指定该域名由哪个DNS服务器来进行解析。

   什么是别名记录(CNAME)?
      也被称为规范名字。这种记录允许您将多个名字映射到同一台计算机。 通常用于同时提供WWW和MAIL服务的计算机。例如,有一台计算机名为“host.mydomain.com”(A记录)。 它同时提供WWW和MAIL服务,为了便于用户访问服务。可以为该计算机设置两个别名(CNAME):WWW和MAIL。 这两个别名的全称就是“www.mydomain.com”和“mail.mydomain.com”。实际上他们都指向“host.mydomain.com”。

   什么是泛域名解析?
      泛域名解析定义为: 客户的域名a.com,之下所设的*.a.com全部解析到同一个IP地址上去。 比如客户设b.a.com就会自已自动解析到与a.com同一个IP地址上去。

   什么是MX记录?
      MX(Mail Exchanger)记录是邮件交换记录,它指向一个邮件服务器,用于电子邮件系统发邮件时根据 收信人的地址后缀来定位邮件服务器。例如,当Internet上的某用户要发一封信给 user@mydomain.com 时,该用户的邮件系统通过DNS查找mydomain.com这个域名的MX记录,如果MX记录存在, 用户计算机就将邮件发送到MX记录所指定的邮件服务器上。
   检查MX记录是否存在的方法
     进行DNS查询的一个非常有用的工具是nslookup,可以使用它来查询DNS中的各种数据。可以在Windows的命令行下直接运行nslookup进入一个交互模式,在这里能查询各种类型的DNS数据。
     DNS的名字解析数据可以有各种不同的类型,有设置这个zone的参数的SOA类型数据,有设置名字对应的IP地址的A类型数据,有设置邮件交换的MX类型数据。这些不同类型的数据均可以通过nslookup的交互模式来查询,在查询过程中可以使用 set type命令设置相应的查询类型。

C:\Documents and Settings\God Father>nslookup
*** Can't find server name for address 192.168.1.1: No response from server
Default Server:  ns.szptt.net.cn
Address:  202.96.134.133

> set type=mx
> tom.com
Server:  ns.szptt.net.cn
Address:  202.96.134.133

Non-authoritative answer:
tom.com MX preference = 10, mail exchanger = tommx.163.net

tom.com nameserver = ns1.tom.com
tom.com nameserver = ns2.tom.com
tommx.163.net   internet address = 202.108.255.210
tommx.163.net   internet address = 202.108.252.141
ns1.tom.com     internet address = 61.135.159.46
ns2.tom.com     internet address = 61.135.159.47

很老的代码了。Jbuilder画图和Eclipse生成的代码确实不一样,其实感觉做界面还是用SWT好些。



/*
* org.gsoft.mail.server.EmsFrame.java
* Copyright  All rights reserved.
*/
package org.gsoft.mail.server;


import javax.swing.*;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Dimension;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.Attributes;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import java.awt.event.*;
import java.util.List;
import java.io.File;
import java.util.LinkedList;
import java.util.Properties;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Message;
import javax.mail.internet.MimeMultipart;
import javax.mail.BodyPart;
import javax.mail.internet.MimeBodyPart;
import javax.activation.FileDataSource;
import javax.activation.DataHandler;
import javax.mail.internet.MimeUtility;
import javax.mail.Multipart;
import java.util.Date;
import javax.mail.Transport;


/**
*
* @author zealvampire
* @version 1.0
*/
public class EmsFrame extends JFrame
{
    /** serialVersionUID */
    private static final long serialVersionUID = 5817303146163930933L;
    
    JLabel senderLabel = new JLabel();
    JTextField senderField = new JTextField();
    JLabel senderPromptLadbel = new JLabel();
    JLabel receiverLabel = new JLabel();
    JTextField receiverField = new JTextField();
    JLabel mailHeadLabel = new JLabel();
    JTextField mailHeadField = new JTextField();
    JList affixList = new JList();
    JLabel affixLabel = new JLabel();
    JButton addButton = new JButton();
    JButton delButton = new JButton();
    JScrollPane jScrollPane1 = new JScrollPane();
    JScrollPane jScrollPane2 = new JScrollPane();
    JButton sendButton = new JButton();
    JLabel contentLabel = new JLabel();
    JEditorPane contentPane = new JEditorPane();
    JButton resetButton = new JButton();
    
    javax.swing.JProgressBar bar = new javax.swing.JProgressBar();

    //附件列表
    private List affixFileList = null;

    public EmsFrame()
    {
        try
        {
            jbInit();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception
    {
        UIManager.setLookAndFeel(
            "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        EmsFrame emsFrame = new EmsFrame();
    }

    private void jbInit() throws Exception
    {
        Font standardFont = new Font("Dialog", 0, 14);
        senderLabel.setFont(standardFont);
        senderLabel.setBorder(null);
        senderLabel.setText("发信人:");
        senderLabel.setBounds(new Rectangle(32, 34, 56, 34));
        this.getContentPane().setLayout(null);
        this.setSize(600, 450);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("EMS 特快专递.");
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        this.setLocation( (int) (screen.getWidth() - 600) / 2,
                         (int) (screen.getHeight() - 450) / 2);

        senderField.setFont(standardFont);
        senderField.setText("anyname@21cn.com");
        senderField.setBounds(new Rectangle(92, 34, 249, 32));
        senderPromptLadbel.setFont(standardFont);
        senderPromptLadbel.setOpaque(false);
        senderPromptLadbel.setText("(支持匿名邮件发送)");
        senderPromptLadbel.setBounds(new Rectangle(366, 58, 135, 29));

        receiverLabel.setFont(standardFont);
        receiverLabel.setText("收件人:");
        receiverLabel.setBounds(new Rectangle(31, 78, 54, 37));
        receiverField.setFont(standardFont);
        receiverField.setText("receiver@21cn.com");
        receiverField.setBounds(new Rectangle(93, 79, 249, 32));

        mailHeadLabel.setFont(standardFont);
        mailHeadLabel.setText("邮件主题:");
        mailHeadLabel.setBounds(new Rectangle(31, 121, 76, 34));
        mailHeadField.setFont(standardFont);
        mailHeadField.setText("测试ems邮件");
        mailHeadField.setBounds(new Rectangle(93, 123, 344, 34));

        affixLabel.setFont(standardFont);
        affixLabel.setText("附件:");
        affixLabel.setBounds(new Rectangle(32, 171, 43, 32));
        addButton.setBounds(new Rectangle(472, 175, 74, 22));
        addButton.setText("添加");
        addButton.addMouseListener(new EmsFrame_addButton_mouseAdapter(this));
        delButton.setBounds(new Rectangle(472, 202, 75, 22));
        delButton.setText("删除");
        delButton.setEnabled(false);
        delButton.addMouseListener(new EmsFrame_delButton_mouseAdapter(this));

        jScrollPane1.setBounds(new Rectangle(93, 172, 342, 54));
        jScrollPane2.setBounds(new Rectangle(92, 237, 343, 161));
        sendButton.setBounds(new Rectangle(472, 279, 74, 25));
        sendButton.setText("发送");
        sendButton.addMouseListener(new EmsFrame_sendButton_mouseAdapter(this));
        contentLabel.setFont(standardFont);
        contentLabel.setText("内容:");
        contentLabel.setBounds(new Rectangle(30, 292, 55, 31));
        contentPane.setFont(standardFont);
        resetButton.setBounds(new Rectangle(472, 311, 74, 24));
        resetButton.setText("重置");
        
        bar.setIndeterminate(true);
        bar.setBounds(50, 400, 500, 12);
        bar.setString("发送中,请稍等..");
        bar.setStringPainted(true);
        bar.setVisible(false);

        this.getContentPane().add(senderLabel, null);
        this.getContentPane().add(senderField, null);
        this.getContentPane().add(receiverLabel, null);
        this.getContentPane().add(receiverField, null);
        this.getContentPane().add(mailHeadLabel, null);
        this.getContentPane().add(jScrollPane1, null);
        jScrollPane1.getViewport().add(affixList, null);
        this.getContentPane().add(mailHeadField, null);
        this.getContentPane().add(delButton, null);
        this.getContentPane().add(affixLabel, null);
        this.getContentPane().add(contentLabel, null);
        this.getContentPane().add(resetButton, null);
        this.getContentPane().add(jScrollPane2, null);
        jScrollPane2.getViewport().add(contentPane, null);
        this.getContentPane().add(senderPromptLadbel, null);
        this.getContentPane().add(addButton, null);
        this.getContentPane().add(sendButton, null);
        
        this.getContentPane().add(bar, null);

        this.setVisible(true);
    }

    /** *//**
     * 处理添加附件消息.
     * @param e 添加按钮消息
     */
    void addButton_mouseClicked(MouseEvent e)
    {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("按住ctrl可选择多个附件:");
        chooser.setMultiSelectionEnabled(true);
        int returnVal = chooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION)
        {
            File[] files = chooser.getSelectedFiles();
            if (files != null)
            {
                if (affixFileList == null)
                    affixFileList = new LinkedList();
                for (int i = 0; i < files.length; ++i)
                    affixFileList.add(files[i].getAbsolutePath());
                affixList.setListData(affixFileList.toArray()); //待定.
                delButton.setEnabled(true);
            }
        }
    }

    /** *//**
     * 处理删除附件动作
     * @param e 删除按钮消息
     */
    void delButton_mouseClicked(MouseEvent e)
    {
        int[] indexes = affixList.getSelectedIndices();
        if (indexes == null || indexes.length <= 0)
        {
            showErrorDialog("删除附件出错!", "请首先选择需要删除的附件!");
            return;
        }

        for (int i = 0; i < indexes.length; ++i)
            affixFileList.set(indexes[i], null);
        for (int i = 0; i < affixFileList.size(); ++i)
        {
            if (affixFileList.get(i) == null)
            {
                affixFileList.remove(i);
                --i;
            }
        }

        affixList.setListData(affixFileList.toArray());
        if (affixFileList.size() <= 0)
            delButton.setEnabled(false);
    }

    private void showErrorDialog(String title, String errorMesg)
    {
        JOptionPane.showMessageDialog(this, errorMesg, title,
                                      JOptionPane.ERROR_MESSAGE);
    }

    /** *//**
     * 处理发送邮件
     * @param e 发送按钮消息
     */
    void sendButton_mouseClicked(MouseEvent e)
    {
//        //暂时默认所有参数合法.
//        MailMessage mesg = new MailMessage(senderField.getText().trim(),
//                                           receiverField.getText().trim(),
//                                           mailHeadField.getText().trim(),
//                                           contentPane.getText().trim());
//        try
//        {
//            sendMail(mesg);
//            if (affixFileList != null)
//            {
//                affixFileList.clear();
//                affixList.setListData(affixFileList.toArray());
//            }
//        }
//        catch (Exception ex)
//        {
//            showErrorDialog("发送邮件失败:", ex.toString());
//            return;
//        }
//
//        JOptionPane.showMessageDialog(this, "邮件发送成功!");
        SendThread thread = new SendThread(this);
        thread.start();


    }
    
    private class SendThread extends Thread {
        private EmsFrame frame = null;
        
        public SendThread (EmsFrame pFrame) {
            this.frame = pFrame;
        }
        public void run() {
            
            MailMessage mesg = new MailMessage(this.frame.senderField.getText().trim(),
                                               this.frame.receiverField.getText().trim(),
                                               this.frame.mailHeadField.getText().trim(),
                                               this.frame.contentPane.getText().trim());
            this.frame.bar.setVisible(true);
            try
            {
                this.frame.sendMail(mesg);
                if (affixFileList != null)
                {
                    affixFileList.clear();
                    affixList.setListData(affixFileList.toArray());
                }
                this.frame.bar.setVisible(false);
                JOptionPane.showMessageDialog(null, "邮件发送成功!");
            }
            catch (Exception ex)
            {
                this.frame.bar.setVisible(false);
                showErrorDialog("发送邮件失败:", ex.toString());
                return;
            }

        }
    }
    

    private void sendMail(MailMessage mesg) throws Exception
    {
        // DNS服务器,如果需要的话手工设置一下。
        String dns = "dns://";
      
       //得到接受方的服务器域名
       String domain = mesg.getTo().substring(mesg.getTo().indexOf('@') + 1);
       Hashtable env = new Hashtable();
       env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
       env.put(Context.PROVIDER_URL, dns);
       DirContext ctx = new InitialDirContext(env);
       Attributes attrs = ctx.getAttributes(domain, new String[] {"MX"});
       if (attrs == null || attrs.size() <= 0) {
           throw new java.lang.IllegalStateException("错误:你的DNS服务器没有相应的MX记录!");
       }
       NamingEnumeration servers = attrs.getAll();
       // 列出所有邮件服务器:
       String smtpHost = null;
       boolean isSend = false;
       StringBuffer buf = new StringBuffer();
       while (servers.hasMore())
       {
           Attribute hosts = (Attribute) servers.next();
           for (int i = 0; i < hosts.size(); ++i)
           {
               smtpHost = (String) hosts.get(i);
               smtpHost = smtpHost.substring(smtpHost.lastIndexOf(' ') + 1);
               try {
                   sendEms(smtpHost, mesg);
                   isSend = true;
                   return;
               } catch (Exception e) {
                   e.printStackTrace();
                   buf.append(e.toString()).append("\r\n");
                   continue;
               }
           }
       }
       if (!isSend) {
           throw new java.lang.IllegalStateException("错误:发送失败," + buf.toString());
       }
      
    }

    /**
     * 特快转递邮件发送
     * @param smtpHost 对方smtp服务器域名
     * @param mesg 发送方信息封装
     * @throws Exception
     */
    private void sendEms(String smtpHost, MailMessage mesg) throws Exception
    {

        Properties p = System.getProperties();
        p.put("mail.smtp.host", smtpHost);
        p.put("mail.smtp.port", "25");
        p.put("mail.smtp.auth", "f");
        Session session = Session.getInstance(p, null);
        session.setDebug(true);

        Message  mimeMessage = new MimeMessage (session);
        mimeMessage.setFrom(new InternetAddress(mesg.getFrom()));//可发匿名信
        mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(mesg.getTo()));
        mimeMessage.setSubject(mesg.getTitle());
        mimeMessage.setHeader("X-Mailer", "JavaMail");
        mimeMessage.setSentDate(new Date());        

        Multipart mimeMultipart = new MimeMultipart();

        //内容部分.
        BodyPart contentBodyPart = new MimeBodyPart();
        contentBodyPart.setContent(mesg.getContent(), "text/html;charset=GB2312");
        mimeMultipart.addBodyPart(contentBodyPart);

        //附件部分
        if (affixFileList != null && affixFileList.size() > 0)
        {
            BodyPart fileBodyPart = null;
            String filePath = null;
            FileDataSource fileDataSource = null;
            for (int i = 0; i < affixFileList.size(); ++i)
            {
                filePath = (String) affixFileList.get(i);
                fileBodyPart = new MimeBodyPart();
                fileDataSource = new FileDataSource(filePath);
                fileBodyPart.setDataHandler(new DataHandler(fileDataSource));
                fileBodyPart.setFileName(MimeUtility.encodeWord(fileDataSource.
                    getName(), "GB2312", null));
                mimeMultipart.addBodyPart(fileBodyPart);
            }
        }

        mimeMessage.setContent(mimeMultipart);
        mimeMessage.setSentDate(new Date());
        mimeMessage.saveChanges();

        //发送
        Transport.send(mimeMessage);
    }



}

class EmsFrame_addButton_mouseAdapter extends java.awt.event.MouseAdapter
{
    EmsFrame adaptee;

    EmsFrame_addButton_mouseAdapter(EmsFrame adaptee)
    {
        this.adaptee = adaptee;
    }
    public void mouseClicked(MouseEvent e)
    {
        adaptee.addButton_mouseClicked(e);
    }
}

class EmsFrame_delButton_mouseAdapter extends java.awt.event.MouseAdapter
{
    EmsFrame adaptee;

    EmsFrame_delButton_mouseAdapter(EmsFrame adaptee)
    {
        this.adaptee = adaptee;
    }
    public void mouseClicked(MouseEvent e)
    {
        adaptee.delButton_mouseClicked(e);
    }
}

class EmsFrame_sendButton_mouseAdapter extends java.awt.event.MouseAdapter
{
    EmsFrame adaptee;

    EmsFrame_sendButton_mouseAdapter(EmsFrame adaptee)
    {
        this.adaptee = adaptee;
    }
    public void mouseClicked(MouseEvent e)
    {
        adaptee.sendButton_mouseClicked(e);
    }
}

class MailMessage
{
    private String from = null;
    private String to   = null;
    private String title   = null;
    private String content = null;

    public MailMessage (String from, String to, String title, String content)
    {
        this.from = from;
        this.to = to;
        this.title = title;
        this.content = content;
    }

    public String getFrom()
    {
        return this.from;
    }

    public String getTo()
    {
        return this.to;
    }

    public String getTitle()
    {
        return this.title;
    }

    public String getContent()
    {
        return this.content;
    }

}




[本日志由 blurxx 于 2009-10-29 01:23 PM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: javamail 匿名
相关日志:
评论: 0 | 引用: 0 | 查看次数: 932
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭