⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtpmailsender.java

📁 短信发送
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/**
 * @CreatedDate Nov 5, 2008
 */
/**
 * @CreatedDate Nov 5, 2008
 */
package com.jdev.mail;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Locale;
import java.util.regex.Pattern;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;

import com.jdev.security.Base64;
import com.jdev.util.LogManager;

/**
 * SMTP邮件发送系统。
 * 
 * 
 * 发件人和收件人的正确格式如下:
 * 
 * 例1: "Sol"<sol@gameeden.org>
 * 例2: Sol<sol@gameeden.org>
 * 例3: <sol@gameeden.org>
 * 例4: sol@gameeden.org
 * 
 * @author Sol
 * @since 1.5
 */
public final class SmtpMailSender {
	/**
	 * 发送成功的常量。
	 */
	public final static boolean SUCCESSFUL = true;

	/**
	 * 发送失败的常量。
	 */
	public final static boolean FAILED = false;

	private final static int PORT = 25;//服务器端口(SMTP服务器和邮件接收服务器的端口均为25)
	private final static int RETRY = 3;//当连接SMTP服务器失败后尝试重新连接的次数(仅用于发送ESMTP邮件)
	private final static int INTERVAL = 1000;//当连接SMTP服务器失败后重新连接的时间间隔(仅用于发送ESMTP邮件)
	private final static int TIMEOUT = 10000;//网络连接的超时时间

	private final static String BOUNDARY;//MIME分格符
	private final static String CHARSET;//虚拟机的默认编码
	private final static Pattern PATTERN;//用于效验邮箱地址的正确性

	private static InitialDirContext dirContext;//用于查询DNS记录

	private final ArrayList<LogManager> logManager;//日志管理器

	private boolean isEsmtp;//发送类型

	private String smtp;//SMTP服务器地址(仅用于发送ESMTP邮件)
	private String user;//用户名(仅用于发送ESMTP邮件)
	private String password;//密码(仅用于发送ESMTP邮件)
	private String sender;//发件人名字
	private String senderAddress;//发件人的E-Mail地址

	static {
		BOUNDARY = "Boundary-=_hMbeqwnGNoWeLsRMeKTIPeofyStu";
		CHARSET = Charset.defaultCharset().displayName();
		PATTERN = Pattern.compile(".+@[^.@]+(\\.[^.@]+)+$");//此处放弃了传统匹配方式,这是为了兼容非英文域名的电子邮箱

		Hashtable<String, String> hashtable = new Hashtable<String, String>();
		hashtable.put("java.naming.factory.initial",
				"com.sun.jndi.dns.DnsContextFactory");

		try {
			dirContext = new InitialDirContext(hashtable);
		} catch (NamingException e) {
		}
	}

	private SmtpMailSender(String from) {
		if (from == null) {
			throw new IllegalArgumentException("参数from不能为null。");
		}

		int leftSign = (from = from.trim()).charAt(from.length() - 1) == '>' ? from
				.lastIndexOf('<')
				: -1;

		senderAddress = leftSign > -1 ? from.substring(leftSign + 1,
				from.length() - 1).trim() : from;

		if (!PATTERN.matcher(senderAddress).find()) {
			throw new IllegalArgumentException("参数from不正确。");
		}

		sender = leftSign > -1 ? from.substring(0, leftSign).trim() : null;
		logManager = new ArrayList<LogManager>();
		isEsmtp = false;

		if (sender != null) {
			if (sender.length() == 0) {
				sender = null;
			} else if (sender.charAt(0) == '"'
					&& sender.charAt(sender.length() - 1) == '"') {
				sender = sender.substring(1, sender.length() - 1).trim();
			}
		}
	}

	private SmtpMailSender(String address, String from, String user,
			String password) {
		this(from);

		isEsmtp = true;
		this.smtp = address;
		this.user = Base64.encode(user.getBytes());
		this.password = Base64.encode(password.getBytes());
	}

	/**
	 * 创建SMTP邮件发送系统实例。
	 * @param from 发件人
	 * @return SMTP邮件发送系统的实例
	 * @throws IllegalArgumentException 如果参数from为null或格式不正确
	 */
	public static SmtpMailSender createSmtpMailSender(String from)
			throws IllegalArgumentException {
		return new SmtpMailSender(from);
	}

	/**
	 * 创建ESMTP邮件发送系统实例。
	 * @param smtp SMTP服务器地址
	 * @param from 发件人
	 * @param user 用户名
	 * @param password 密码
	 * @return SMTP邮件发送系统的实例
	 * @throws IllegalArgumentException 如果参数from为null或格式不正确
	 */
	public static SmtpMailSender createESmtpMailSender(String smtp,
			String from, String user, String password)
			throws IllegalArgumentException {
		return new SmtpMailSender(smtp, from, user, password);
	}

	/**
	 * 发送邮件。
	 * @param to 收件人
	 * @param subject 主题
	 * @param content 正文
	 * @param attachments 附件
	 * @param isHtml 使用网页形式发送
	 * @param isUrgent 紧急邮件
	 * @return 是否发送成功
	 * @throws IllegalArgumentException 如果参数to为null或格式不正确
	 */
	public boolean sendMail(String to, String subject, String content,
			File[] attachments, boolean isHtml, boolean isUrgent)
			throws IllegalArgumentException {
		if (to == null) {
			throw new IllegalArgumentException("参数to不能为null。");
		}

		int leftSign = (to = to.trim()).charAt(to.length() - 1) == '>' ? to
				.lastIndexOf('<') : -1;

		String addresseeAddress = leftSign > -1 ? to.substring(leftSign + 1,
				to.length() - 1).trim() : to;//收件人的E-Mail地址

		if (!PATTERN.matcher(addresseeAddress).find()) {
			throw new IllegalArgumentException("参数to不正确。");
		}

		String addressee = leftSign > -1 ? to.substring(0, leftSign).trim()
				: null;//收件人名字
		boolean needBoundary = attachments != null && attachments.length > 0;

		Socket socket = null;
		InputStream in = null;
		OutputStream out = null;
		byte[] data;

		try {
			if (addressee != null) {
				if (addressee.length() == 0) {
					addressee = null;
				} else if (addressee.charAt(0) == '"'
						&& addressee.charAt(addressee.length() - 1) == '"') {
					addressee = addressee.substring(1, addressee.length() - 1)
							.trim();
				}
			}

			if (isEsmtp) {
				for (int k = 1;; k++) {
					try {
						log("连接: 主机:\"" + smtp + "\" 端口:\"" + PORT + "\"");
						socket = new Socket(smtp, PORT);
						break;
					} catch (IOException e) {
						log("错误: 连接失败" + k + "次");

						if (k == RETRY) {
							return FAILED;
						}

						try {
							Thread.sleep(INTERVAL);
						} catch (InterruptedException ie) {
						}
					}
				}

				in = socket.getInputStream();
				out = socket.getOutputStream();

				if (response(in) != 220) {
					return FAILED;
				}
			} else {
				log("状态: 创建邮件接收服务器列表");
				String[] address = parseDomain(parseUrl(addresseeAddress));

				if (address == null) {
					return FAILED;
				}

				for (int k = 0; k < address.length; k++) {
					try {
						log("连接: 主机:\"" + address[k] + "\" 端口:\"" + PORT + "\"");

						socket = new Socket(address[k], PORT);

						in = socket.getInputStream();
						out = socket.getOutputStream();

						if (response(in) != 220) {
							return FAILED;
						}

						break;
					} catch (IOException e) {
						log("错误: 连接失败");
					}
				}
			}

			if (in == null || out == null) {
				return FAILED;
			}

			socket.setSoTimeout(TIMEOUT);

			sendString("HELO " + parseUrl(senderAddress), out);
			sendNewline(out);

			if (response(in) != 250) {
				return FAILED;
			}

			if (isEsmtp) {
				sendString("AUTH LOGIN", out);
				sendNewline(out);

				if (response(in) != 334) {
					return FAILED;
				}

				sendString(user, out);
				sendNewline(out);

				if (response(in) != 334) {
					return FAILED;
				}

				sendString(password, out);
				sendNewline(out);

				if (response(in) != 235) {
					return FAILED;
				}
			}

			sendString("MAIL FROM: <" + senderAddress + ">", out);
			sendNewline(out);

			if (response(in) != 250) {
				return FAILED;
			}

			sendString("RCPT TO: <" + addresseeAddress + ">", out);
			sendNewline(out);

			if (response(in) != 250) {
				return FAILED;
			}

			sendString("DATA", out);
			sendNewline(out);

			if (response(in) != 354) {
				return FAILED;
			}

			sendString("From: "
					+ (sender == null ? senderAddress : getBase64String(sender)
							+ " <" + senderAddress + ">"), out);
			sendNewline(out);
			sendString("To: "
					+ (addressee == null ? addresseeAddress
							: getBase64String(addressee) + " <"
									+ addresseeAddress + ">"), out);
			sendNewline(out);
			sendString("Subject: " + getBase64String(subject), out);
			sendNewline(out);
			sendString("Date: "
					+ new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z (z)",
							Locale.US).format(new Date()), out);
			sendNewline(out);
			sendString("MIME-Version: 1.0", out);
			sendNewline(out);

			if (needBoundary) {
				sendString("Content-Type: multipart/mixed; BOUNDARY=\""
						+ BOUNDARY + "\"", out);
				sendNewline(out);
			} else {
				if (isHtml) {
					sendString("Content-Type: text/html; charset=\"" + CHARSET
							+ "\"", out);
					sendNewline(out);
				} else {
					sendString("Content-Type: text/plain; charset=\"" + CHARSET
							+ "\"", out);
					sendNewline(out);
				}
			}

			sendString("Content-Transfer-Encoding: base64", out);
			sendNewline(out);

			if (isUrgent) {
				sendString("X-Priority: 1", out);
				sendNewline(out);
			} else {
				sendString("X-Priority: 3", out);
				sendNewline(out);
			}

			sendString("X-Mailer: BlackFox Mail[Copyright(C) 2007 Sol]", out);
			sendNewline(out);

			log("发送: ");
			sendNewline(out);

			if (needBoundary) {
				sendString("--" + BOUNDARY, out);
				sendNewline(out);

				if (isHtml) {
					sendString("Content-Type: text/html; charset=\"" + CHARSET
							+ "\"", out);
					sendNewline(out);
				} else {
					sendString("Content-Type: text/plain; charset=\"" + CHARSET
							+ "\"", out);
					sendNewline(out);
				}

				sendString("Content-Transfer-Encoding: base64", out);
				sendNewline(out);

				log("发送: ");
				sendNewline(out);
			}

			data = (content != null ? content : "").getBytes();

			for (int k = 0; k < data.length; k += 54) {
				sendString(Base64
						.encode(data, k, Math.min(data.length - k, 54)), out);
				sendNewline(out);
			}

			if (needBoundary) {
				RandomAccessFile attachment = null;
				int fileIndex = 0;
				String fileName;
				int k;
				data = new byte[54];

				try {
					for (; fileIndex < attachments.length; fileIndex++) {
						fileName = attachments[fileIndex].getName();
						attachment = new RandomAccessFile(
								attachments[fileIndex], "r");

						sendString("--" + BOUNDARY, out);
						sendNewline(out);
						sendString(
								"Content-Type: "
										+ MimeTypeFactory.getMimeType(fileName
												.indexOf(".") == -1 ? "*"
												: fileName.substring(fileName
														.lastIndexOf(".") + 1))
										+ "; name=\""

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -