在这篇文章中,自己花了不少的时间编写一个简单的 E-mail 发送端程序,原理是跟 Telnet 中所用的相差很少,程序运行效果图如下:
在这个代码中,有几个注意点强调一下:
1、使用 Socket 与 SMTP 邮件服务器取得连接,注意 SMTP 服务器的主机名;
2、使用 data 命令时,若写了 subject (主题)之后,邮件的正文部分必须与 subject 之间有一个空行,即“回车+换行”,在代码中则是 \r\n ;
3、同样需要将发件人的邮箱用户名、密码进行 BASE64 编码之后再传给 SMTP 服务器;
4、程序在编译时仍然存在警告,这是由于 sun.misc.BASE64Encoder 类是存在于 rt.jar 包中的,由于 JDK 会更新升级,可能会导致该包中的某些类发生变化而不可用,所以编译器会发出警告。
此外,写了这些代码,也发现了一些问题:
1、smtp.qq.com 和 smtp.sina.com 邮件服务器不知道为什么不能用,也就是说,当发件人的邮箱地址是 qq 或者 sina 时,这个程序不管用了,状态应答码也看不懂。在我的测试当中,只有 smtp.163.com 可以用,明明都是在官网查到这几个 SMTP 服务器的,怎么不能用呢?真奇怪。有哪位朋友知道的希望能告诉我,谢谢!
2、在下面的 SimpleMailSender 类中的 sendEmail() 方法中,有些重复代码让人感到疑惑,但是没办法,我暂时还弄不懂…
3、重大发现:QQ 邮箱接收邮件的速度比 163 邮箱、sina 邮箱要快上可能有数十倍,真让我惊讶。此外,使用 nslookup 命令查询 smtp.qq.com 的主机名时,发现它有好多台 SMTP 服务器,至少比 163 的 3 台多出 5 台,腾讯真够强大;
4、虽然说写了这个程序可以恶意地不停给某个邮箱发邮件,但是我发现,当我用一个 sina 邮箱连续发送了几十封邮件给固定的另一个邮箱之后,该 sina 邮箱再想发邮件就会被拒绝,小心哟。
代码如下:
// 邮件
class E_Mail {
String from;
String to;
String subject;
String content;
String userName;
String pwd;
public E_Mail(String from, String to, String subject,
String content, String userName, String pwd) {
this.from = from;
this.to = to;
this.subject = subject;
this.content = content;
this.userName = this.toBASE64(userName);
this.pwd = this.toBASE64(pwd);
}
/**
* 在 E_Mail 类中进行用户名、密码的转码工作
*/
private String toBASE64(String str) {
return (new sun.misc.BASE64Encoder().encode(str.getBytes()));
}
}
// 简单的邮件发送端类,实现发送功能
public class SimpleMailSender {
private String smtpServer;
private int port = 25;
private Socket socket;
BufferedReader br;
PrintWriter pw;
/**
* 根据发件人的邮箱地址确定SMTP邮件服务器
*/
private void initServer(String from) {
if(from.contains("@163")) {
this.smtpServer = "smtp.163.com";
}else if(from.contains("@126")) {
this.smtpServer = "smtp.126.com";
}else if(from.contains("@sina")) {
this.smtpServer = "smtp.sina.com";
}else if(from.contains("@qq")) {
this.smtpServer = "smtp.qq.com";
}
}
public void sendEmail(E_Mail email) {
try {
this.initServer(email.from);
this.socket = new Socket(smtpServer, port);
this.br = this.getReader(socket);
this.pw = this.getWriter(socket);
// 开始组装发送邮件的命令序列
send_Receive(null); // 接收连接SMTP服务器成功的信息
send_Receive("ehlo hao");
send_Receive("auth login");
send_Receive(email.userName);
send_Receive(email.pwd);
send_Receive("mail from:<" + email.from + ">");
send_Receive("rcpt to:<" + email.to + ">");
send_Receive("data");
// 邮件内容
pw.println("from:" + email.from);
pw.println("to:" + email.to);
// 主题与正文之间一定要空一行,即加上"\r\n"
pw.println("subject:" + email.subject + "\r\n");
// 在控制台打印邮件内容
System.out.println("from:" + email.from);
System.out.println("to:" + email.to);
System.out.println("subject:" + email.subject + "\r\n");
System.out.println(email.content);
// 邮件正文
pw.println(email.content);
// 一定记得正文以"."结束
send_Receive(".");
send_Receive("quit");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 每发送一条命令,必须在命令后面加上"\r\n",
* 则同时打印出smtp邮件服务器的相应状态码
* @param command
*/
private void send_Receive(String command) throws IOException{
if(command != null) {
// 向SMTP邮件服务器发送命令,一定要记得加上"\r\n"
pw.print(command + "\r\n");
pw.flush();
System.out.println("用户 >> " + command);
}
char [] response = new char[1024];
br.read(response);
System.out.println(response);
}
/**
* 获取 Socket 的输出流
*/
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut, true);
}
/**
* 获取 Socket 的输入流
*/
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
return new BufferedReader(new InputStreamReader(socketIn));
}
// 测试
public static void main(String[] args) {
new MailSenderGUI();
}
}
// 邮件发送程序界面
class MailSenderGUI extends JFrame implements ActionListener {
private JLabel userNameLabel;
private JTextField userNameField;
private JLabel pwdLabel;
private JPasswordField pwdField;
private JLabel fromLabel;
private JTextField fromField;
private JLabel toLabel;
private JTextField toField;
private JLabel subjectLabel;
private JTextField subjectField;
private JLabel contentLabel;
private JTextArea contentArea;
private JButton sendBtn;
private JButton cancelBtn;
private E_Mail email;
private SimpleMailSender mailSender;
public MailSenderGUI() {
this.init();
this.mailSender = new SimpleMailSender();
}
private void init() {
this.fromLabel = new JLabel("发件人邮箱地址:");
this.fromField = new JTextField(25);
this.userNameLabel = new JLabel("用户名:");
this.userNameField = new JTextField(25);
this.pwdLabel = new JLabel("密码:");
this.pwdField = new JPasswordField(25);
this.toLabel = new JLabel("收件人邮箱地址:");
this.toField = new JTextField(25);
this.subjectLabel = new JLabel("邮件主题:");
this.subjectField = new JTextField(20);
this.contentLabel = new JLabel("邮件正文:");
this.contentArea = new JTextArea(15, 20);
this.setTitle("蚂蚁-->简单邮件发送器");
this.setBounds(200, 30, 500, 500);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.sendBtn = new JButton("发送");
this.cancelBtn = new JButton("重置");
this.sendBtn.addActionListener(this);
this.cancelBtn.addActionListener(this);
JPanel upPanel = new JPanel(new GridLayout(6, 2, 5, 5));
upPanel.add(fromLabel);
upPanel.add(fromField);
upPanel.add(userNameLabel);
upPanel.add(userNameField);
upPanel.add(pwdLabel);
upPanel.add(pwdField);
upPanel.add(toLabel);
upPanel.add(toField);
upPanel.add(subjectLabel);
upPanel.add(subjectField);
upPanel.add(contentLabel);
this.add(upPanel, BorderLayout.NORTH);
this.add(contentArea, BorderLayout.CENTER);
JPanel downPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
downPanel.add(sendBtn, BorderLayout.SOUTH);
downPanel.add(cancelBtn, BorderLayout.SOUTH);
this.add(downPanel, BorderLayout.SOUTH);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.sendBtn) {
this.email = new E_Mail(
this.fromField.getText(),
this.toField.getText(),
this.subjectField.getText(),
this.contentArea.getText(),
this.userNameField.getText(),
new String(this.pwdField.getPassword())
);
this.mailSender.sendEmail(this.email);
} else if (e.getSource() == this.cancelBtn) {
this.fromField.setText(null);
this.toField.setText(null);
this.subjectField.setText(null);
this.contentArea.setText(null);
}
}
}
本文转自 xxxx66yyyy 51CTO博客,原文链接:http://blog.51cto.com/haolloyin/351508,如需转载请自行联系原作者