Internet Mail system & JavaMail
Internet Mail Protocol
Simple Mail Transfer Protocol (SMTP) is the de facto standard for e-mail transmissions across the Internet. Formally SMTP is defined in RFC 821 (STD 10) as amended by RFC 1123 (STD 3) chapter 5. The protocol used today is also known as ESMTP and defined in RFC 2821

SMTP is a relatively simple, text-based protocol, in which one or more recipients of a message are specified (and in most cases verified to exist) along with the message text and possibly other encoded objects. The message is then transferred to a remote server using a procedure of queries and responses between the client and server. Either an end-user's email client, a.k.a. MUA (Mail User Agent), or a relaying server's MTA (Mail Transport Agents) can act as an SMTP client.
The SMTP client initiates a TCP connection to server's port 25 (unless overridden by configuration). SMTP is a "push" protocol that does not allow one to "pull" messages from a remote server on demand. To do this a mail client must use POP3 or IMAP. An email client knows the outgoing mail SMTP server from its configuration. An email client requires the name or the IP address of an SMTP server as part of its configuration. The server will deliver messages on behalf of the user.SMTP
The Simple Mail Transfer Protocol (SMTP) is defined by RFC 821 . It defines the mechanism
for delivery of e-mail. In the context of the JavaMail API, your JavaMail-based program will
communicate with your company or Internet Service Provider's (ISP's) SMTP server. That
SMTP server will relay the message on to the SMTP server of the recipient(s) to eventually
be acquired by the user(s) through POP or IMAP. This does not require your SMTP server to
be an open relay, as authentication is supported, but it is your responsibility to ensure the
SMTP server is configured properly. There is nothing in the JavaMail API for tasks like
configuring a server to relay messages or to add and remove e-mail accounts.
POP
POP stands for Post Office Protocol. Currently in version 3, also known as POP3, RFC 1939
defines this protocol. POP is the mechanism most people on the Internet use to get their
mail. It defines support for a single mailbox for each user. That is all it does, and that is also
the source of a lot of confusion. Much of what people are familiar with when using POP, like
the ability to see how many new mail messages they have, are not supported by POP at all.
These capabilities are built into programs like Eudora or Microsoft Outlook, which remember
things like the last mail received and calculate how many are new for you. So, when using
the JavaMail API, if you want this type of information, you have to calculate it yourself.

IMAP
IMAP is a more advanced protocol for receiving messages. Defined in RFC 2060 , IMAP
stands for Internet Message Access Protocol, and is currently in version 4, also known as
IMAP4. When using IMAP, your mail server must support the protocol. You can't just change
your program to use IMAP instead of POP and expect everything in IMAP to be supported.
MIME
MIME stands for Multipurpose Internet Mail Extensions. It is not a mail transfer protocol.
Instead, it defines the content of what is transferred: the format of the messages,
attachments, and so on. There are many different documents that take effect here: RFC 822
, RFC 2045 , RFC 2046 , and RFC 2047 . As a user of the JavaMail API, you usually don't
need to worry about these formats. However, these formats do exist and are used by your
programs.
MIME[마임]은 아스키 데이터만을 처리할 수 있는 원래의 인터넷 전자우편 프로토콜, 즉 SMTP를 확장하여 오디오, 비디오, 이미지, 응용프로그램, 기타 여러가지 종류의 데이터 파일들을 주고받을 수 있도록 기능이 확장된 프로토콜이다. 1991년에 SMTP를 확장하여 인터넷 클라이언트 및 서버들이 아스키 텍스트 이외의 다른 종류의 데이터들도 인식하고 처리할 수 있도록 할 것을, 벨 코어의 Nathan Borenstein이 Internet Engineering Task Force에 제안하였다. 그 결과로, 새로운 파일 형식들이 IP가 지원하는 파일 형식으로서 메일에 추가되었다.
서버들은 어떤 웹 전송에라도 시작부분에 MIME 헤더를 집어넣으며, 클라이언트들은 헤더가 나타내는 데이터 형식에 따라 이를 재생시키기 위한 적절한 응용프로그램을 선택한다. 이러한 재생용 프로그램들 중 일부는 웹 클라이언트, 즉 브라우저에 기본적으로 탑재되며 (예를 들어 모든 브라우저는 HTML 파일의 처리뿐 아니라 GIF와 JPG 이미지를 보여줄 수 있는 능력을 가지고 있다), 그 외의 프로그램들은 필요할 때마다 다운로드된다.
JavaMail
You can send or fetch e-mail through your Java application or servlet using the JavaMail API.
You use the JavaMail API where as JavaMail implementation providers implement the JavaMail API to give you a JavaMail client (Java JAR file). Sun gives you mail.jar
which has Sun's SMTP, POP3 and IMAP client implementations along with the JavaMail API. This is sufficient to send and receive e-mail but not to read or post to newgroups which use NNTP.
JavaMail API를 이용하여 예제에서 다루고자 하는 메일전달 영역:SMTP Client

JavaMail 프로그래밍 환경설정
JDK, JavaMail 1.4, JavaBeans Activation Framework(JAF)1.1
JDK가 설치되어 있다면 나머지 2가지 API를 썬사의 홈페이지에서 다운로드하고 라이브러리를 JDK에 복사한다. 다음에 제시한 페이지에 접속하면 다운로드할 수 있다.
http://java.sun.com/products/javamail/downloads/index.html (JavaMail API download)
http://java.sun.com/products/javabeans/jaf/downloads/index.html (JAF download)
javamail-1_4_1.zip 압축해제하여 mail.jar 파일을 찾아 Java/JDK/jre/lib/ext 안에 복사해 둔다.
jaf-1_1_1.zip 압축해제하여 activation.jar 파일을 찾아 역시 같은 곳에 복사해 둔다.
웹 프로그래밍에 사용하기 위해서는 Tomcat/common/lib/ 안에 위에서 언급한 2개의 jar 파일을 복사해 두면 된다.
SMTP Server 설치
Windows 2003에서 윈도우구성요소 추가기능을 이용하여 SMTP 서버를 설치한다.
SMTP Server 설치 후 설정
JavaMail 프로그램을 실행할 컴퓨터에 SMTP 서버가 설치되어 있다면 다음과 같이 설정해 주세요.
Windows SMTP 설치 후, 시작>프로그램>관리도구>인터넷 정보서비스(IIS)관리>기본SMTP가상서버>
>속성>액세스>릴레이>아래목록만>추가>127.0.0.1입력>확인>적용>확인
SMTP 서버 시작
강사 컴퓨터에 설치된 SMTP 서버를 사용하려는 경우 즉, 다른 컴퓨터에 설치되어 있는 SMTP 서버를 JavaMail 프로그램에서 사용하려고 한다면......
SMTP서버가 설치되어 있는 컴퓨터에서, 시작>프로그램>관리도구>인터넷 정보서비스(IIS)관리>기본SMTP가상서버>속성>액세스>릴레이>아래목록만 제외>확인>적용>확인
SMTP 서버 시작
The Session Class
The Session class defines global and per-user mail-related properties that define the interface between a mail-enabled client and the network. JavaMail system components use the Session object to set and get specific properties. The Session class also provides a default authenticated session object that desktop applications can share. The Session class is a final concrete class. It cannot be subclassed.
The Session class also acts as a factory for Store and Transport objects that implement specific access and transport protocols. By calling the appropriate factory method on a Session object, the client can obtain Store and Transport objects that support specific protocols.
Properties props = new Properties(); // fill props with any information Session session = Session.getDefaultInstance(props, null);Or, you can create a unique session with
getInstance()
:Properties props = new Properties(); // fill props with any information Session session = Session.getInstance(props, null);
Message
Once you have your Session
object, it is time to move on to creating the message to send. This is done with a type of Message
. Being an abstract class, you must work with a subclass, in most cases javax.mail.internet.MimeMessage
. A MimeMessage
is a email message that understands MIME types and headers, as defined in the different RFCs. Message headers are restricted to US-ASCII characters only, though non-ASCII characters can be encoded in certain header fields.
To create a Message
, pass along the Session
object to the MimeMessage
constructor:
MimeMessage message = new MimeMessage(session);
Note: There are other constructors, like for creating messages from RFC822-formatted input streams. |
Once you have your message, you can set its parts, as Message
implements the Part
interface (with MimeMessage
implementing
). The basic mechanism to set the content is the MimePart
setContent()
method, with arguments for the content and the mime type:
message.setContent("Hello", "text/plain");
If, however, you know you are working with a MimeMessage
and your message is plain text, you can use its setText()
method which only requires the actual content, defaulting to the MIME type of text/plain:
message.setText("Hello");
For plain text messages, the latter form is the preferred mechanism to set the content. For sending other kinds of messages, like HTML messages, use the former. More on HTML messages later though.
For setting the subject, use the setSubject()
method:
message.setSubject("First");
The MimeMessage Class
The MimeMessage class extends Message and implements MimePart. This class
implements an email message that conforms to the RFC822 and MIME standards.
// Set FROM:
m.setFrom(new InternetAddress("jmk@Sun.COM"));
// Set TO:
InternetAddress a[] = new InternetAddress[1];
a[0] = new InternetAddress("javamail@Sun.COM");
m.setRecipients(Message.RecipientType.TO, a);
// Set content
m.setContent(data, "text/plain");
// Send message
Transport.send(m);
MimeMessage example
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
// Send a simple, single part, text/plain e-mail
public class TestEmail {
public static void main(String[] args) {
// SUBSTITUTE YOUR EMAIL ADDRESSES HERE!!!
String to = "vipan@vipan.com";
String from = "vipan@vipan.com";
// SUBSTITUTE YOUR ISP'S MAIL SERVER HERE!!!
String host = "smtp.yourisp.net";
// Create properties, get Session
Properties props = new Properties();
// If using static Transport.send(),
// need to specify which host to send it to
props.put("mail.smtp.host", host);
// To see what is going on behind the scene
props.put("mail.debug", "true");
Session session = Session.getInstance(props);
try {
// Instantiatee a message
Message msg = new MimeMessage(session);
//Set message attributes
msg.setFrom(new InternetAddress(from));
InternetAddress[] address = {new InternetAddress(to)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Test E-Mail through Java");
msg.setSentDate(new Date());
// Set message content
msg.setText("This is a test of sending a " +
"plain text e-mail through Java.\n" +
"Here is line 2.");
//Send the message
Transport.send(msg);
}
catch (MessagingException mex) {
// Prints all nested (chained) exceptions as well
mex.printStackTrace();
}
}
}//End of class
The MimeBodyPart Class
The MimeBodyPart class extends BodyPart and implements the MimePart interface. This class represents a Part inside a Multipart. MimeBodyPart implements a Body Part as defined by RFC2045, Section 2.5.
The getBodyPart(int index) returns the MimeBodyPart object at the given index. MimeMultipart also allows the client to fetch MimeBodyPart objects based on their Content-IDs.
The addBodyPart method adds a new MimeBodyPart object to a MimeMultipart as a step towards constructing a new multipart MimeMessage.
The MimeMultipart Class
The MimeMultipart class extends Multipart and models a MIME multipart content within a message or a body part.
A MimeMultipart is obtained from a MimePart containing a ContentType attribute set to multipart, by invoking that part's getContent method.
The client creates a new MimeMultipart object by invoking its default constructor. To create a new multipart MimeMessage, create a MimeMultipart object (or its subclass); use set methods to fill in the appropriate MimeBodyParts; and finally, use setContent(Multipart) to insert it into the MimeMessage.
MimeMultipart also provides a constructor that takes an input stream positioned at the beginning of a MIME multipart stream. This class parses the input stream and creates the child body parts.
The getSubType method returns the multipart message MIME subtype. The subtype defines the relationship among the individual body parts of a multipart message. More semantically complex multipart subtypes are implemented as subclasses of MimeMultipart, providing additional methods that expose specific functionality.
Note that a multipart content object is treated like any other content. When parsing a MIME Multipart stream, the JavaMail implementation uses the JAF framework to locate a suitable DataContentHandler for the specific subtype and uses that handler to create the appropriate Multipart instance. Similarly, when generating the output stream for a Multipart object, the appropriate DataContentHandler is used to generate the stream.
Address
Once you've created the Session
and the Message
, as well as filled the message with content, it is time to address your letter with an
. Like Address
Message
, Address
is an abstract class. You use the javax.mail.internet.InternetAddress
class.
To create an address with just the email address, pass the email address to the constructor:
Address address = new InternetAddress("president@whitehouse.gov");
If you want a name to appear next to the email address, you can pass that along to the constructor, too:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush");
You will need to create address objects for the message's from field as well as the to field. Unless your mail server prevents you, there is nothing stopping you from sending a message that appears to be from anyone.
Once you've created the addresses, you connect them to a message in one of two ways. For identifying the sender, you use the setFrom()
and setReplyTo()
methods.
message.setFrom(address)
If your message needs to show multiple from addresses, use the addFrom()
method:
Address address[] = ...; message.addFrom(address);
For identifying the message recipients, you use the addRecipient()
method. This method requires a Message.RecipientType
besides the address.
message.addRecipient(type, address)
The three predefined types of address are:
- Message.RecipientType.TO
- Message.RecipientType.CC
- Message.RecipientType.BCC
So, if the message was to go to the vice president, sending a carbon copy to the first lady, the following would be appropriate:
Address toAddress = new InternetAddress("vice.president@whitehouse.gov");
Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");
message.addRecipient(Message.RecipientType.TO, toAddress);
message.addRecipient(Message.RecipientType.CC, ccAddress);
The JavaMail API provides no mechanism to check for the validity of an email address. While you can program in support to scan for valid characters (as defined by RFC 822) or verify the MX (mail exchange) record yourself, these are all beyond the scope of the JavaMail API.
Authenticator
Like the java.net
classes, the JavaMail API can take advantage of an Authenticator
to access protected resources via a username and password. For the JavaMail API, that resource is the mail server. The JavaMail Authenticator
is found in the javax.mail
package and is different from the java.net
class of the same name. The two don't share the same Authenticator
as the JavaMail API works with Java 1.1, which didn't have the java.net
variety.
To use the Authenticator
, you subclass the abstract class and return a
instance from the PasswordAuthentication
getPasswordAuthentication()
method. You must register the Authenticator
with the session when created. Then, your Authenticator
will be notified when authentication is necessary. You could popup a window or read the username and password from a configuration file (though if not encrypted it is not secure), returning them to the caller as a PasswordAuthentication
object.
Properties props = new Properties(); // fill props with any information Authenticator auth = new MyAuthenticator(); Session session = Session.getDefaultInstance(props, auth);
Transport
The final part of sending a message is to use the Transport
class. This class speaks the protocol-specific language for sending the message (usually SMTP). It's an abstract class and works something like Session
. You can use the default version of the class by just calling the static send()
method:
Transport.send(message);
Or, you can get a specific instance from the session for your protocol, pass along the username and password (blank if unnecessary), send the message, and close the connection:
message.saveChanges(); // implicit with send() Transport transport = session.getTransport("smtp"); transport.connect(host, username, password); transport.sendMessage(message, message.getAllRecipients()); transport.close(); |
Environment Properties
This section lists some of the environment properties that are used by the JavaMail APIs. The JavaMail javadocs contain additional information on properties supported by JavaMail.
mail.transport.protocol :Specifies the default Transport Protocol.
mail.protocol.host : Specifies the protocol-specific default Mail server.
mail.protocol.port :
메시지에 파일을 첨부하여 전송하는 예제
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.io.*;
import java.util.*;
/*
* 메시지에 파일을 첨부하여 전송하는 예제
*/
public class JavaMail_Append {
public static void main(String[] args) {
try{
//set up the default parameters.
Properties props = new Properties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", "192.168.2.90");
props.put("mail.smtp.port", "25");
//create the session and create the new mail message
Session mailSession = Session.getInstance(props);
Message msg = new MimeMessage(mailSession);
//송신자 메일주소
msg.setFrom(new InternetAddress("President@SUN.COM"));
//수신자 메일주소
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("cwisky@paran.co.kr"));
msg.setSentDate(new Date());
msg.setSubject("JavaMail 테스트");
/*첨부파일 없이 메시지만 전송할 경우 다음 라인처럼 텍스트를 설정하고 전송하면 된다.
* msg.setText("Hello! from my first java e-mail...Testing!!/n");
* Transport.send(msg);
*/
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText("테스트용 메일의 내용입니다.");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
File file = new File("JavaMail_Append.java");
FileDataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setFileName(fds.getName());
multipart.addBodyPart(messageBodyPart);
// Put parts in message
msg.setContent(multipart);
// Send the message
Transport.send(msg);
System.out.println("E-mail successfully sent!!");
}catch(Exception e){
e.printStackTrace();
}
}
}
Webmail Infrastructures

JSP 에서 메일을 전송하는 예제
이 예제를 실행하려면 HTML 폼을 작성하고 이 페이지로 메일 정보를 전송해야 한다.
<%@ page contentType="text/html;charset=euc-kr"%>
<%@ page import="java.util.*, javax.mail.*, javax.mail.internet.*"%>
<%--
mail.jar, activation.jar, mailapi.jar 를
Tomcat 의 Common/lib 안에 복사한다.
Tomcat을 다시 실행한다.
SMTP 서버를 실행한다.
SMTP 등록정보에서 '액세스' 항목과 '릴레이' 항목을 이용이 가능하도록 설정해야 한다.
--%>
<%!
public String kr(String s) {
try {
s = (s == null) ? "" : new String(s.getBytes("8859_1"),"KSC5601");
} catch (java.io.UnsupportedEncodingException uee) {}
return s;
}
%>
<html><head><title>메일전송결과</title>
<%
// 사용자가 입력한 메일 전송 자료를 저장
String mailFrom = null;
String mailTo = null;
String title = null;
String contents = null;
String htmltag = null;
mailFrom = kr(request.getParameter("from"));
mailTo = kr(request.getParameter("to"));
title = kr(request.getParameter("title"));
contents = kr(request.getParameter("content"));
htmltag = "<font color=BLUE size=2>";
contents = htmltag + contents;
// Session을 생성하기 위해 java.util.Properties 클래스를
// 생성하고
// 기본 Session을 생성하고 할당합니다.
Session msgSession = Session.getDefaultInstance(System.getProperties(), null);
%>
</head>
<body bgcolor="#D0E0FF">
<center>
<%
try {
// Message 클래스의 객체를 Session을 이용해 생성합니다.
MimeMessage msg = new MimeMessage(msgSession);
InternetAddress from = new InternetAddress(mailFrom);
msg.setFrom(from);
InternetAddress to = new InternetAddress(mailTo);
msg.setRecipient(Message.RecipientType.TO, to);
msg.setSubject(title);
msg.setContent(contents, "text/html; charset=EUC-KR");
Transport.send(msg);
%>
요청하신 메일 전송이 완료되었습니다.<br>
좋은 하루 되세요.<br>
<%
}
catch (MessagingException e) {
e.printStackTrace();
%>
<center>죄송합니다. 메일 전송이 실패하였습니다.<br>
관리자에게 문의하세요.<br>
<a href="#" onClick="history.back()">돌아가기</a>
<% } %>
</center></body></html>