Java Mail Sender Util

2010-08-12 20:41 by hackerzhou

因为项目需要实现用java发送邮件,故使用Java Mail类库来做一个工具类,之前也写过一些使用java mail发送邮件的代码,但是大都通用性不强,不是不支持SSL就是不能加附件,要不就是代码太琐碎不精简。这次写了一个较为通用的版本,支持SSL,支持附件,类变量尽可能精简,使用的类库是JavaMail 1.4.3,下载地址:http://www.oracle.com/technetwork/java/index-138643.html

发现Java Mail只支持socks代理, 不支持http代理,Java Mail的官方文档是这么说的:

Q: How do I configure JavaMail to work through my proxy server?
A: JavaMail does not currently support accessing mail servers through a web proxy server. One of the major reasons for using a proxy server is to allow HTTP requests from within a corporate network to pass through a corporate firewall. The firewall will typically block most access to the Internet, but will allow requests from the proxy server to pass through. In addition, a mail server inside the corporate network will perform a similar function for email, accepting messages via SMTP and forwarding them to their ultimate destination on the Internet, and accepting incoming messages and sending them to the appropriate internal mail server.

If your proxy server supports the SOCKS V4 or V5 protocol ( http://www.socks.nec.com/aboutsocks.html, RFC1928) and allows anonymous connections, you can tell the Java runtime to direct all TCP socket connections to the SOCKS server. See the Networking Properties guide for the latest documentation of the socksProxyHost and socksProxyPort properties. These are system-level properties, not JavaMail session properties. They can be set from the command line when the application is invoked, for example: java -DsocksProxyHost=myproxy .... This facility can be used to direct the SMTP, IMAP, and POP3 communication from JavaMail to the SOCKS proxy server. Note that setting these properties directs all TCP sockets to the SOCKS proxy, which may have negative impact on other aspects of your application.

Without such a SOCKS server, if you want to use JavaMail to directly access mail servers outside the firewall, the firewall will need to be configured to allow such access. JavaMail does not support access through a HTTP proxy web server.

于是使用HTTP代理的想法只能作罢,有些小遗憾。

import java.io.File;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

/**
 * @author hackerzhou
 * @version 2010-8-12 09:06:31
 */
public class MailUtil {
	private Session session = null;
	private Properties properties = System.getProperties();
	private Authenticator authenticator = null;
	private HashMap<String, String> mailAttachment = new HashMap<String, String>();

	public static void main(String[] args) {
		String[] to = { "***@***.com" };
		String[] cc = { "***@***.com" };
		String content = "<html><head></head><body><img src=\"cid:Sunset.jpg\"/></body></html>";
		String subject = "Test HTML";
		MailUtil util = new MailUtil("***.***.com", false, null, null, false,
				null);
		util.addAttachment("D:\\test.jpg");
		util.send("***@***.com", to, cc, subject, content);
	}

	/**
	 * No SMTP auth and no SSL
	 */
	public MailUtil(String smtpHost) {
		this(smtpHost, false, null, null, false, null);
	}

	/**
	 * SMTP auth with SSL
	 */
	public MailUtil(String smtpHost, final String username,
			final String password, String sslPort) {
		this(smtpHost, true, username, password, true, sslPort);
	}

	/**
	 * SMTP auth without SSL
	 */
	public MailUtil(String smtpHost, final String username,
			final String password) {
		this(smtpHost, true, username, password, false, null);
	}

	/**
	 * All in one setting
	 */
	public MailUtil(String smtpHost, boolean needAuth, final String username,
			final String password, boolean isSSL, String sslPort) {
		setSMTPHost(smtpHost);
		if (isSSL) {
			enableSSL(sslPort);
		}
		if (needAuth) {
			enableAuth(username, password);
		}
		session = getSession(needAuth);
	}

	/**
	 * Add attachment to email.
	 */
	public void addAttachment(String filePath) {
		if (isStringEmpty(filePath)) {
			throw new RuntimeException("[Error] Attachment filepath is empty!");
		}
		mailAttachment.put(filePath, new File(filePath).getName());
	}

	/**
	 * Send email from specified from-address to specified to-addresses /
	 * cc-addresses with given subject and content.
	 * <p>
	 * If already call addAttachment, the method will try to include them into
	 * email body
	 */
	public void send(String fromAddress, String[] toEmailAddresses,
			String[] ccEmailAddresses, String subject, String content) {
		MimeMessage message = new MimeMessage(session);
		MimeMultipart multipart = new MimeMultipart();
		try {
			message.setSubject(subject);
			message.setRecipients(Message.RecipientType.TO,
					emailToInternetAddressArray(toEmailAddresses));
			message.setRecipients(Message.RecipientType.CC,
					emailToInternetAddressArray(ccEmailAddresses));
			message.addFrom(InternetAddress.parse(fromAddress));
			BodyPart mainBody = new MimeBodyPart();
			mainBody.setContent(content, "text/html;charset=UTF-8");
			multipart.addBodyPart(mainBody);
			for (Entry<String, String> e : mailAttachment.entrySet()) {
				BodyPart bodyPart = new MimeBodyPart();
				bodyPart.setDataHandler(new DataHandler(new FileDataSource(e
						.getKey())));
				bodyPart.setFileName(e.getValue());
				bodyPart.setHeader("Content-ID", e.getValue());
				multipart.addBodyPart(bodyPart);
			}
			message.setContent(multipart);
			message.saveChanges();
			Transport.send(message, message.getAllRecipients());
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

	private void setSMTPHost(String smtpHost) {
		if (smtpHost == null) {
			throw new RuntimeException("[Error] SMTP Host is empty!");
		}
		properties.setProperty("mail.smtp.host", smtpHost);
	}

	private Session getSession(boolean needAuth) {
		mailAttachment.clear();
		return needAuth ? session = Session.getInstance(properties,
				authenticator) : Session.getInstance(properties);
	}

	private void enableAuth(final String username, final String password) {
		if (username == null || password == null) {
			throw new RuntimeException("[Error] Username or password is empty!");
		}
		properties.put("mail.smtp.auth", "true");
		authenticator = new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password);
			}
		};
	}

	private void enableSSL(String sslPort) {
		if (isStringEmpty(sslPort)) {
			throw new RuntimeException("[Error] SSL port is empty!");
		}
		properties.setProperty("mail.smtp.socketFactory.class",
				"javax.net.ssl.SSLSocketFactory");
		properties.setProperty("mail.smtp.socketFactory.fallback", "false");
		properties.setProperty("mail.smtp.port", sslPort);
		properties.setProperty("mail.smtp.socketFactory.port", sslPort);
	}

	private boolean isStringEmpty(String s) {
		return s == null || s.length() == 0;
	}

	private InternetAddress[] emailToInternetAddressArray(String[] email)
			throws AddressException {
		if (email == null) {
			return new InternetAddress[0];
		}
		InternetAddress[] addresses = new InternetAddress[email.length];
		for (int i = 0; i < email.length; i++) {
			addresses[i] = new InternetAddress(email[i]);
		}
		return addresses;
	}
}
本文基于 署名 2.5 中国大陆 许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 hackerzhou 并包含 原文链接
发表评论

本文有 2 条评论

  1. paying
    2011-11-10 09:42

    发送邮件出现邮件内容中文乱码

    • hackerzhou
      2011-11-11 14:52

      你的string是什么编码的?注意mainBody.setContent(content, “text/html;charset=UTF-8”);这一行。

发表评论