Java发送电子邮件避免smtp中继服务器并直接发送到MX服务器

时间:2015-12-09 14:24:01

标签: java email smtp javamail javax.mail

我尝试直接向目标MX服务器发送电子邮件,避免使用中继smtp服务器。 有条理地,可以让名称服务器列表对dns服务器进行查询。 因此,使用此类http://www.eyeasme.com/Shayne/MAILHOSTS/mailHostsLookup.html,我可以获得域的邮件交换服务器列表。

所以,一旦我有了,我该如何继续发送电子邮件?我应该使用javax.mail或如何?如果是,我该如何配置呢?

1 个答案:

答案 0 :(得分:8)

好的,假设我们这样做了。

我们执行DNS-Lookup来获取收件人域的MX记录。下一步是连接到该服务器并传递消息。由于作为MX运行的主机必须侦听端口25并需要接受未加密的通信,我们可以这样做:

  • 获取MX主机名
  • 创建Session并将mail.smtp.host设置为所述服务器
  • 发送邮件

我们会获得什么?

  • 不再需要中继服务器。

我们会失去什么?

  • 我们会慢一些(DNS-Lookup,与世界各地目标主机的连接)
  • 我们必须执行完整的错误处理(如果主机已关闭怎么办?我们什么时候重试?)
  • 我们必须通过垃圾邮件预防来实现。因此,至少我们的服务器必须解析回我们发送电子邮件的域。

结论:我不这样做。有一些替代方案(安装本地sendmail / postfix无论如何)完全能够为我们做硬SMTP工作,同时仍然简化了我们需要用Java做的工作来获取邮件。

工作示例

这是通过使用DNS解析的MX条目为gmail.com向我发送电子邮件的代码。猜猜发生了什么?被归类为垃圾邮件因为谷歌说“它很可能不是来自Jan”

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.naming.*;
import javax.naming.directory.*;

public class DirectMail {

    public static void main(String[] args) {
        try {
            String[] mx = getMX("gmail.com");
            for(String mxx : mx) {
                System.out.println("MX: " + mxx);
            }
            Properties props = new Properties();
            props.setProperty("mail.smtp.host", mx[0]);
            props.setProperty("mail.debug", "true");
            Session session = Session.getInstance(props);
            MimeMessage message = new MimeMessage(session);
            message.setFrom("XXXXXXXXXXXXXXXXXXXX@gmail.com");
            message.addRecipient(RecipientType.TO, new InternetAddress("XXXXXXXXXXXXXXXXXXXX@gmail.com"));
            message.setSubject("SMTP Test");
            message.setText("Hi Jan");
            Transport.send(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String[] getMX(String domainName) throws NamingException {
        Hashtable<String, Object> env = new Hashtable<String, Object>();

        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
        env.put(Context.PROVIDER_URL, "dns:");

        DirContext ctx = new InitialDirContext(env);
        Attributes attribute = ctx.getAttributes(domainName, new String[] {"MX"});
        Attribute attributeMX = attribute.get("MX");
        // if there are no MX RRs then default to domainName (see: RFC 974)
        if (attributeMX == null) {
            return (new String[] {domainName});
        }

        // split MX RRs into Preference Values(pvhn[0]) and Host Names(pvhn[1])
        String[][] pvhn = new String[attributeMX.size()][2];
        for (int i = 0; i < attributeMX.size(); i++) {
            pvhn[i] = ("" + attributeMX.get(i)).split("\\s+");
        }

        // sort the MX RRs by RR value (lower is preferred)
        Arrays.sort(pvhn, (o1, o2) -> Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]));

        String[] sortedHostNames = new String[pvhn.length];
        for (int i = 0; i < pvhn.length; i++) {
            sortedHostNames[i] = pvhn[i][1].endsWith(".") ? 
                pvhn[i][1].substring(0, pvhn[i][1].length() - 1) : pvhn[i][1];
        }
        return sortedHostNames;     
    }
}