Java Mail 첨부파일 처리

옛날 sun의 메일 관련 기술 문서인데 썬이 사라지면서 함께 사라졌던 문서. 우연히 인터넷에서 찾게되어 기록용으로 남겨둠.

ADVANCED HTML EMAIL

The April 26, 2004 Tech Tip titled Using the JavaMail API to Send HTML Email, showed how to use the JavaMail API to send HTML email that is also readable by text browsers. But the email from that tip was text only -- it didn't include images. In the following tip, you'll see how to use the JavaMail API to send HTML email that contains embedded images.

 

Email Image Links Considered Harmful

You might sometimes receive HTML email that includes images. Sometimes the message's HTML code links to the image on the sender's server using an <img> tag, and a src attribute that identifies the image's URL, like this:

   <img src="http://originating_server/images/image.jpg" />

The browser accesses these images just as if it were displaying an image in a Web page. Unfortunately, unscrupulous spammers have used this mechanism as a sneaky way to record who visits their site. They do this by including a unique id in the image src URL, and then saving the ID along with your email address. Such an image URL might look like this:

   <img src="http://evilspammer.com/images/x.jpg?userid=12" />

When you visit the site, the server looks up your email address by the ID, and singles you out for special treatment. Unknowingly, you've just told a spammer that you're considering their product, so they may choose to market to you more aggressively. Worse, you've told them that your email address is "live", so it can be sold at a higher price to yet other spammers.

To protect your privacy, many Web-based (and other) email clients don't display images in HTML emails. While blocking image URLs in emails protects your privacy as a user, it can complicate your life as an application developer. Fortunately, you have another option: embedded images.

 

Embedding Images in HTML Emails

An alternative to placing absolute URLs to images in your HTML is to include the images as attachments to the email. You then use relative URLs to those images in your HTML code. The email format for attachments is defined by MIME (Multipurpose Internet Email Extensions), the standard protocol specifications for Internet email.

MIME has a mechanism that can be used to send an email containing HTML, plus attachments that contain the images the HTML references. A specification called RFC 2387 defines the MIME content type "multipart/related". A message in multipart/related format contains a collection of objects that are meant to be used together. For the purposes of this tip, that means an HTML file and the images it uses.

Each attachment in a multipart/related message has a unique identifier called its content-id. The content-id is defined by the application that sends the email, and is assigned when the message is constructed. The HTML can reference the image in an attachment by using the protocol prefix cid: plus the content-id of the attachment. For example, if an attachment has content-idimage.part.1@x.org, then an HTML file in the same message could use the image inline with the following tag:

  <img src="cid:image.part.1@x.org" />

A mail reading program (either a standalone program, or a web-based email interface) would render the tag above using the image with the given content-id.

 

Providing a Text Alternative

As described in the April 2004 tip, you can use a multipart/alternative content type to include alternative versions of the same object. In doing this, you allow the receiving program (the mail reader) to choose the most appropriate content type. The "most appropriate" content type may be defined by the capabilities of the mail reader or by user preferences.

The sample code that accompanies this tip includes both a text version of the transmitted file and an HTML version with embedded images. The content-type of the message itself ismultipart/alternative. The message's first body part is the text alternative. The second body part is the HTML alternative. Images are included in the second part (the HTML) by defining the second part's content-type as multipart/related. The first related body part is the HTML code (text/html), and subsequent body parts are attachments containing any images (image/jpg) used by the first (HTML) related body part.

Here is a diagram of the multipart message sent by the sample code.

사용자 삽입 이미지

 

JavaMail Sample Code

The class that sends the email, HtmlEmailer.java, uses the JavaMail API to send an email with the structure defined above. The program takes a single argument: the name of a properties file that configures the program's behavior. The first section of the code loads the properties file and uses its values to create and initialize a new MimeMessage.

       Properties props = new Properties();
       props.load(new FileInputStream(propfile));
        
       Session session = Session.getInstance(props, null);
       MimeMessage msg = new MimeMessage(session);
  
       InternetAddress from =
          new InternetAddress((String)props.get
            ("ttjun2004.from"));
    
       InternetAddress to =
          new InternetAddress((String)props.get
            ("ttjun2004.to"));
    
       msg.setFrom(from);
       msg.addRecipient(Message.RecipientType.TO, to);
       msg.setSubject((String)props.get("ttjun2004.subject"));

The next section of the code creates the multipart/alternative section of the message by constructing a MimeMultipart object. It also creates the first alternative body part from the text file name supplied in the props file.

       // Create a "related" Multipart message
       Multipart mp = new MimeMultipart("alternative");

       // Read text file, load it into a BodyPart, 
       // and add it to the message.
       String textfile = (String)props.get("ttjun2004.txtfile");
       BodyPart alt_bp1 = getFileBodyPart(textfile);
       mp.addBodyPart(alt_bp1);

Method getFileBodyPart is simply a convenience method for creating body parts to use as file attachments:

   public BodyPart getFileBodyPart(String filename)
      throws javax.mail.MessagingException {
         BodyPart bp = new MimeBodyPart();
         bp.setDataHandler(new DataHandler
            (new FileDataSource(filename)));
         return bp;
   }

The DataHandler loads the file. The JavaMail classes identify and correctly set the file's Content-type header.

Returning to the class's sendmail method, the next several lines of code create amultipart/related Multipart container, and load it with its first body part: the HTML file contents.

     // Include an HTML version with images. The HTML file
     // is a Multipart of type "related". Inside it are
     // two BodyParts: the HTML file and an image
     String htmlfile = (String)props.get("ttjun2004.htmlfile");
     Multipart html_mp = new MimeMultipart("related");

     // Get the HTML file
     BodyPart rel_bph = getFileBodyPart(htmlfile);
     html_mp.addBodyPart(rel_bph);

The next task is to get the image file. The simple example program allows only a single image file, but more files would be easy to add. The properties file contains the name of the image file to attach, and also defines the content-id. The content-id must match the content-id used by the HTML file. The HTML file can use the same content-id multiple times, but the content-id should be globally unique: no two content-ids should ever be the same.

The code below creates a new MimeBodyPart for the image, and loads it with a FileDataSourcethat acquires the image file contents. The code then initializes several of the image properties. It then adds the image as the second related part of the HTML alternative.

     // Get the image file
     String imagefile = (String)props.get("ttjun2004.imagefile");
     String cid = (String)props.get("ttjun2004.cid");
     MimeBodyPart rel_bpi = new MimeBodyPart();
     FileDataSource ifds = new FileDataSource(imagefile);

     // Initialize and add the image file to the html body part
     rel_bpi.setFileName(ifds.getName());
     rel_bpi.setText("Image 1");
     rel_bpi.setDataHandler(new DataHandler(ifds));
     rel_bpi.setHeader("Content-ID", "<" + cid + ">");
     rel_bpi.setDisposition("inline");
     html_mp.addBodyPart(rel_bpi);

Two of the initializations above merit special attention. First, if the Content-ID header is not set, the image will not be identifiable by the HTML file. In this case, the image will not appear. By convention, the Content-ID is enclosed in angle-brackets. Also, a MIME message's content-id must be URL-encoded (using the same encoding as an HTTP GET query string). Second, the call tosetDisposition("inline") configures the image to appear inline in the HTML, rather than separately at the bottom of the message. This is necessary because some mail readers show images inline only when explicitly told to do so.

The final few lines of the sendmail method create a new MimeBodyPart to wrap theMimeMultipart that forms the second alternative in the message. This code adds the second alternative to the main message body, adds the main message body to the Message object, and then uses the JavaMail Transport class to send the message.

     // Create the second BodyPart of the multipart/alternative,
     // set its content to the html multipart, and add the
     // second bodypart to the main multipart.
     BodyPart alt_bp2 = new MimeBodyPart();
     alt_bp2.setContent(html_mp);
     mp.addBodyPart(alt_bp2);

     // Set the content for the message and transmit
     msg.setContent(mp);
     Transport.send(msg);

The default content (text file, html file, and image) simulates a newsletter that provides a "Space Image of the Day". In this case, the "Space Image of the Day" is a picture of the planet Saturn, accompanied by some text describing the picture. Experiment with this class by defining your own HTML content, and linking and attaching images. Don't forget to change the parameters in the properties file to reflect your changes.

 

2015/09/10 15:22 2015/09/10 15:22
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

JavaMail :: 인증을 요하는 메일 SMTP에 접속하는 방법

2007/08/22 16:33

서비 JAVA , , ,

얼마전 인증을 해야하는 SMTP에 연결해야 했는데 그 방법 때문에 매우 고민했었습니다.
Mail API에서 Authenticator는 제공을 하면서 ID와 PW를 설정하는 부분이 없어서
참 난감했었습니다. 영어 실력이 짧아서 관련 Document를 읽어보다가 못찾고
다만 API에 있는 Session 클래스의
getInstance(Properties prop, Authenticator auth) 메소드가 마음에 걸려
혹시나 하는 마음으로 만들어 봤었는데 잘 되더군요.
sendmail 과 qmail 및 윈도기반 smtp server 몇 곳을 테스트 해봤는데 잘 되었습니다.

클래스 전체 소스는 다음과 같습니다.

/*
* MyAuthenticator.java
* 2002.05.27.
* Hyunho Kim(falllove@ducc.or.kr)
*
* Copyrightⓒ 2002 FancyArts Corps. All rights reserved.
*/

/**
* SMTP Authenticator
*/
public final class MyAuthenticator extends javax.mail.Authenticator {

    private String id;
    private String pw;

    public MyAuthenticator(String id, String pw) {
        this.id = id;
        this.pw = pw;
    }

    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
        return new javax.mail.PasswordAuthentication(id, pw);
    }

}

사용하실 때는 session을 얻기 전에 프로퍼티에 mail.smtp.auth 항목을 추가하시고
MyAuthenticator의 인스턴스를 하나 만드셔서 인자로 넘기시면 됩니다.

Properties prop = new Properties();
prop.put("mail.smtp.host", "smtp_host_name");
prop.put("mail.smtp.auth", "true");

MyAuthenticator auth = new MyAuthenticator("smpt_id", "smtp_pw");

// 새로운 메일 세션
Session mailSession = Session.getInstance(props, auth);
// or Session mailSession = Session.getDefaultInstance(props, auth);

정말 간단하죠^^;; 정말 암 것도 없는데 전에 이것을 하기 위해서 그 많은 글을 뒤적일
때는 못찾겠더라구요. 전 만들긴 했었지만 실제 서비스는 sendmail에서
localhost relay를 허용해서 사용하고 인증없이 발송하고 있습니다.
2007/08/22 16:33 2007/08/22 16:33
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다