JNDI(二)编写具有SMTP服务器功能的邮件发送程序

(1)按例程6-6编写一个名为SMTPSender.java的程序,这个程序向属于多个不同域的收件人发送邮件,它直接连接到每个收件人所在域的SMTP服务器进行邮件发送。

例程6-6  SMTPSender.java

 

import javax.naming.Context;

import javax.naming.NamingException;

import javax.naming.directory.Attribute;

import javax.naming.directory.Attributes;

import javax.naming.directory.DirContext;

import javax.naming.directory.InitialDirContext;

 

import java.util.Properties;

import java.util.Date;

import javax.mail.Session;

import javax.mail.Transport;

import javax.mail.internet.InternetAddress;

import javax.mail.Message;

import javax.mail.internet.MimeMessage;

 

 

public class SMTPSender

{

    public static void main(String[] args) throws Exception

    {

        //下面是邮件要群发给的多个收件人地址

        String [] to = {"[email protected]","[email protected]",

                            "[email protected]","[email protected]"};

    

        //创建Session对象

        Properties props = new Properties();

        /*mail.smtp.localhost属性用于设置SMTP协议的EHLO命令中的

        主机名,其他SMTP服务器可能需要使用这个主机名确定发件SMTP

        服务器的身份,这个信息可以从JavaMail的javadocs文档中的

        com.sun.mail.smtp包的帮助页面内查看到。

        */

        props.setProperty("mail.smtp.localhost","mail.itcast.cn");

        Session session = Session.getInstance(props);

        session.setDebug(true);

 

        Message msg = createMessage(session);

        for(int i=0; i<to.length; i++)

        {

            try

{

                sendMessage(session,msg,to[i]);

            }

catch(Exception e)

            {

                e.printStackTrace();

            }

        }

    }

   

    public static Message createMessage(Session session)

                throws Exception

    {

 

        String from = "[email protected] ";//发件人地址

        String subject = "SMTPSender demo";//邮件主题

        String body = "SMTPSender demo";//邮件内容

       

        //创建代表邮件的MimeMessage对象,不包含收件人地址

        MimeMessage msg = new MimeMessage(session);

        msg.setFrom(new InternetAddress(from));

        msg.setSentDate(new Date());

        msg.setSubject(subject);

        msg.setText(body);

        return msg;    

    }

   

    public static void sendMessage(Session session,Message msg,String to)

            throws Exception

    {

        //设置邮件内容的收件人并生成邮件消息内容

        msg.setRecipients(Message.RecipientType.TO,

                            InternetAddress.parse(to));

        msg.saveChanges();

       

        //连接收件人地址所在的SMTP服务器并发送邮件

        Transport transport = session.getTransport("smtp");

        String domain = to.substring(to.indexOf("@")+1);

        String smtpServer = getSmtpServer(domain,null);

        transport.connect(smtpServer,null,null);

        transport.sendMessage(msg,

                          msg.getRecipients(Message.RecipientType.TO));

        transport.close();     

    }

   

    public static String getSmtpServer(String domain,String dnsServer)

                        throws Exception

    {

        DirContext ctx = new InitialDirContext();

        Attributes attrsMx = null;

        if(dnsServer != null)

        {

            attrsMx = ctx.getAttributes("dns:" + "//" + dnsServer +

                                    "/" + domain, new String[]{"MX"});

        }

        else

        {

            attrsMx = ctx.getAttributes("dns:" + "/" + domain, new String[]{"MX"});        

        }          

 

        String recordMx = (String)attrsMx.get("MX").get();

        String smtpServer = recordMx.substring(

                            recordMx.indexOf(" ") + 1);

        return smtpServer;

    }

}

 


实际的SMTP服务器程序要比上面的程序复杂得多,它们每天要向大量的其他SMTP服务器发送大量的邮件,当它们连接上一台其他的SMTP服务器并发送一封邮件后,是否要立即与这个服务器断开连接呢?这就是一个比较难以处理的问题了,如果不断开连接,而随后一段时间内又没有要发送给该SMTP服务器的邮件了,这样就造成网络连接资源浪费;如果发送一封邮件后立即断开与该SMTP服务器的连接,而随后的邮件又是要发送到的该SMTP服务器,又要重新与该SMTP服务器建立连接,这样明显是一种低效率的方法。关于这个问题,有兴趣的读者可以去看一些开源的SMTP服务器程序的源代码,我们就不再这里讨论如何解决这些问题了。

(2)在Windows命令行窗口中编译并运行这个java程序,通常情况下,这个程序发送邮件的过程都会以失败告终,如图6.15所示。

图6.15

出现图6.15中的错误是因为现在的大多数SMTP服务器都增加了一些防垃圾邮件的措施,如果邮件发送程序以SMTP服务器的身份向它们发送邮件,它们要求运行该邮件发送程序的计算机必须在Internet上注册了主机名(也就是A记录),并且这台计算机的IP地址没有被列入进它们的黑名单,而我和读者们使用的计算机往往都无法满足这些条件。

对于sina这样的大型网站,它们提供了完全独立的SMTP服务器来分别与普通邮件客户端程序和其他SMTP服务器进行通信。邮件客户端程序连接的SMTP服务器是smtp.sina.com.cn,smtp.sina.com.cn服务器总是要求对方进行用户身份验证。其他smtp服务器连接的sina的SMTP服务器是sina.com域中MX记录所对应的计算机,例如,sinamx.sina.com.cn,这些注册成了MX记录的计算机不要求对方进行用户身份验证,但也采取各种方式来防止对方发送垃圾邮件。显然,smtp.sina.com.cn是不能被注册为MX记录的,因为它需要对方传递用户身份信息,其他SMTP无法根本无法与之正常通信。

对于小型网站,它们用同一台SMTP服务器来与普通邮件客户端程序和其他SMTP服务器进行通信,它们通常根据对方在ehlo命令中提供的主机名是否与该计算机的ip地址反向解析到的主机名一致来判断对方是普通的邮件客户端程序,还是其他SMTP服务器。如果对方在ehlo命令中指定的主机名与对方的IP地址不匹配,小型网站的SMTP服务器程序则认为对方是普通的邮件客户端程序,需要对方传递用户认证信息;如果对方在ehlo命令中指定的主机名与对方的IP地址匹配,小型网站的SMTP服务器程序则认为对方也是一台SMTP服务器,不需要对方提供用户认证信息即可直接发送邮件。

 


你可能感兴趣的:(JNDI(二)编写具有SMTP服务器功能的邮件发送程序)