先写一个小例子,用来展示如何使用MailToURLConnection 来发送邮件 import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; /** * This program sends e-mail using a mailto: URL */ public class SendMail { public static void main(String[] args) { try { // If the user specified a mailhost, tell the system about it. if (args.length >= 1) System.getProperties().put("mail.host", args[0]); // A Reader stream to read from the console BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // Ask the user for the from, to, and subject lines System.out.print("From: "); String from = in.readLine(); System.out.print("To: "); String to = in.readLine(); System.out.print("Subject: "); String subject = in.readLine(); // Establish a network connection for sending mail URL u = new URL("mailto:" + to); // Create a mailto: URL URLConnection c = u.openConnection(); // Create its URLConnection c.setDoInput(false); // Specify no input from it c.setDoOutput(true); // Specify we'll do output System.out.println("Connecting..."); // Tell the user System.out.flush(); // Tell them right now c.connect(); // Connect to mail host PrintWriter out = // Get output stream to host new PrintWriter(new OutputStreamWriter(c.getOutputStream())); // We're talking to the SMTP server now. // Write out mail headers. Don't let users fake the From address out.print("From: \"" + from + "\" <" + System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName() + ">\r\n"); out.print("To: " + to + "\r\n"); out.print("Subject: " + subject + "\r\n"); out.print("\r\n"); // blank line to end the list of headers // Now ask the user to enter the body of the message System.out.println("Enter the message. " + "End with a '.' on a line by itself."); // Read message line by line and send it out. String line; for (;;) { line = in.readLine(); if ((line == null) || line.equals(".")) break; out.print(line + "\r\n"); } // Close (and flush) the stream to terminate the message out.close(); // Tell the user it was successfully sent. System.out.println("Message sent."); } catch (Exception e) { // Handle any exceptions, print error message. System.err.println(e); System.err.println("Usage: java SendMail [<mailhost>]"); } } }
openConncetion方法就是构造了一个MailToURLConnection对象。
接下来我们看看其中的原理:sun.net.www.protocol.mailto.MailToURLConnection的实现
其中connect 方法源码如下(可以看到这个方法就是初始化了 一个SmtpClient 对象)
public void connect() throws IOException { this.client = new SmtpClient(this.connectTimeout); this.client.setReadTimeout(this.readTimeout); }
SmtpClient构造函数如下: mailhost是邮件服务器地址,可以看到会从系统属性中读取mail.host,如果不存在默认为localhost, 然后就开始连接服务器。 public SmtpClient(int var1) throws IOException { this.setConnectTimeout(var1); try { this.mailhost = (String)AccessController.doPrivileged(new GetPropertyAction("mail.host")); if (this.mailhost != null) { this.openServer(this.mailhost); return; } } catch (Exception var4) { ; } try { this.mailhost = "localhost"; this.openServer(this.mailhost); } catch (Exception var3) { this.mailhost = "mailhost"; this.openServer(this.mailhost); } }
其中openServer 的源码如下:这段代码的意思 就是 先创建一个连接,这里默认邮件服务器端口号是25,然后发送一个helo命令
private void openServer(String var1) throws IOException { this.mailhost = var1; this.openServer(this.mailhost, 25); this.issueCommand("helo " + InetAddress.getLocalHost().getHostName() + "\r\n", 250); }
其中 openServer 的方法源码: .可以看到这里创建了一个客户端socket
public void openServer(String var1, int var2) throws IOException, UnknownHostException {
if (this.serverSocket != null) {
this.closeServer();
}
this.serverSocket = this.doConnect(var1, var2);
try {
this.serverOutput = new PrintStream(new BufferedOutputStream(this.serverSocket.getOutputStream()), true, encoding);
} catch (UnsupportedEncodingException var4) {
throw new InternalError(encoding + "encoding not found", var4);
}
this.serverInput = new BufferedInputStream(this.serverSocket.getInputStream());
}
doConnect 源码如下: protected Socket doConnect(String var1, int var2) throws IOException, UnknownHostException { Socket var3; if (this.proxy != null) { if (this.proxy.type() == Type.SOCKS) { var3 = (Socket)AccessController.doPrivileged(new PrivilegedAction<Socket>() { public Socket run() { return new Socket(NetworkClient.this.proxy); } }); } else if (this.proxy.type() == Type.DIRECT) { var3 = this.createSocket(); } else { var3 = new Socket(Proxy.NO_PROXY); } } else { var3 = this.createSocket(); } if (this.connectTimeout >= 0) { var3.connect(new InetSocketAddress(var1, var2), this.connectTimeout); } else if (defaultConnectTimeout > 0) { var3.connect(new InetSocketAddress(var1, var2), defaultConnectTimeout); } else { var3.connect(new InetSocketAddress(var1, var2)); } if (this.readTimeout >= 0) { var3.setSoTimeout(this.readTimeout); } else if (defaultSoTimeout > 0) { var3.setSoTimeout(defaultSoTimeout); } return var3; }
getOutputStream源码如下:
public synchronized OutputStream getOutputStream() throws IOException {
if (this.os != null) {
return this.os;
} else if (this.is != null) {
throw new IOException("Cannot write output after reading input.");
} else {
this.connect();
String var1 = ParseUtil.decode(this.url.getPath());
this.client.from(this.getFromAddress());
this.client.to(var1);
this.os = this.client.startMessage();
return this.os;
}
}
public PrintStream startMessage() throws IOException {
this.issueCommand("data\r\n", 354);
try {
this.message = new SmtpPrintStream(this.serverOutput, this);
} catch (UnsupportedEncodingException var2) {
throw new InternalError(encoding + " encoding not found", var2);
}
return this.message;
}