Dev Note/Java2011. 8. 10. 21:16

java mail API를 이용하여 GMail의 SMTP를 이용하여 메일을 발송하는 것에 대해 아주 간략하게 알아본다.
메일을 발송하기 위해서는 Java Mail API와 GMail 계정이 필요하다. (GMail SMTP는 SSL로 계정 인증을 해야 사용이 가능하다.)

발송되는 메일의 텍스트는 HTML이며, UTF-8이다. Text나 다른 캐릭터셋을 원한다면 조금 수정하면 된다.
기능은 첨부파일이 있는 메일과 없는 메일만 구분하여 제공한다.

import java.io.File;

import java.util.Date;

import java.util.Properties;

 

import javax.activation.DataHandler;

import javax.activation.FileDataSource;

import javax.mail.Authenticator;

import javax.mail.Message;

import javax.mail.Multipart;

import javax.mail.PasswordAuthentication;

import javax.mail.Session;

import javax.mail.Transport;

import javax.mail.internet.InternetAddress;

import javax.mail.internet.MimeBodyPart;

import javax.mail.internet.MimeMessage;

import javax.mail.internet.MimeMultipart;

import javax.mail.internet.MimeUtility;

 

/**

 * <PRE>

 * SmtpMailer class

 * SMTP 이용하여 메일을 발송한다.

 * </PRE>

 *

 * @author ukzzang

 * @version v0.8, 2011. 8. 2.

 *

 *          <PRE>

 * - History

 *            2011. 8. 2., ukzzang, 최초작성.

 * </PRE>

 */

public class GmailSmtpSender {

 

    // gmail smtp default info

    public static final String DEFAULT_TRANSPORT_PROTOCOLC = "smtp";

    public static String DEFAULT_SMTP_SOCKET_FACTORY_CLASS 
           
"javax.net.ssl.SSLSocketFactory"
;

    public static String DEFAULT_SMTP_HOST = "smtp.gmail.com";

    public static int DEFAULT_SMTP_PORT = 465;

 

    private Properties props = null;

 

    /**

      * constructor

      */

    public GmailSmtpSender() {

        this(DEFAULT_SMTP_HOST, DEFAULT_SMTP_PORT,

                           DEFAULT_SMTP_SOCKET_FACTORY_CLASS);

    }

 

    /**

      * constructor

      *

      * @param host smtp host (domain or ip)

      * @param port smtp port

      * @param socketFactoryClassName smtp socket factory class name

      */

    public GmailSmtpSender(String host, int port, String socketFactoryClassName)
    {

        props = new Properties();

 

        // 기본 프로퍼티 설정

        props.put("mail.smtp.starttls.enable", "true");

        props.put("mail.smtp.auth", "true");

        props.put("mail.transport.protocol", DEFAULT_TRANSPORT_PROTOCOLC);

 

        // 지정 가능 프로퍼티 설정

        props.put("mail.smtp.host", host);

        props.setProperty("mail.smtp.socketFactory.class",

                           socketFactoryClassName);

        props.put("mail.smtp.port", String.valueOf(port)); 

    }

 

    /**

      * SMTP 이용하여 메이을 발송한다. (인증을 위해 Gmail 계정정보가 필요하며, 첨부파일 처리는 없다.)

      *

      * @param authId 인증 아이디

      * @param authPasswd 인증 패스워드

      * @param from 보내는 사람 메일 주소

      * @param fromName 보내는 사람 표현 이름

      * @param to 받는 메일 주소

      * @param cc 참조 메일 주소

      * @param bcc 숨은 참조 메일 주소

      * @param subject 메일 제목

      * @param content 메일 내용

      * @throws Exception

      */

    public void sendSmtpMail(String authId, String authPasswd, String from,
           
String fromName, String[] to, String[] cc, String[] bcc,

            String subject, String content) throws Exception {

        Message msg = createMessage(authId, authPasswd, from, fromName, 
                to, cc, 
bcc, null); // create message

 

        // subject & content

        msg.setSubject(subject);

        msg.setSentDate(new Date());

        msg.setContent(content, "text/html;charset=utf-8");

 

        Transport.send(msg); // send mail

    }

 

    /**

      * SMTP 이용하여 메이을 발송한다. (인증을 위해 Gmail 계정정보가 필요하며, 첨부파일 처리는 없다.)

      *

      * @param authId 인증 아이디

      * @param authPasswd 인증 패스워드

      * @param from 보내는 사람 메일 주소

      * @param fromName 보내는 사람 표현 이름

      * @param to 받는 메일 주소

      * @param cc 참조 메일 주소

      * @param bcc 숨은 참조 메일 주소

      * @param subject 메일 제목

      * @param content 메일 내용

      * @param attachFiles 첨부파일

      * @throws Exception

      */

    public void sendSmtpMail(String authId, String authPasswd, String from,

            String fromName, String[] to, String[] cc, String[] bcc,

            String subject, String content, File[] attachFiles)

            throws Exception {

        Message msg = createMessage(authId, authPasswd, from, fromName, to, cc,

                bcc, attachFiles); // create message

 

        // subject & content

        msg.setSubject(subject);

        msg.setSentDate(new Date());

 

        Object contentObj = msg.getContent();

        if (contentObj != null && contentObj instanceof Multipart) {

            MimeBodyPart contentPart = new MimeBodyPart();

            contentPart.setText(content);

            contentPart.setHeader("Content-Type", "text/html;charset=utf-8");

 

            Multipart mPart = (Multipart) contentObj;

            mPart.addBodyPart(contentPart);

        } else {

            msg.setContent(content, "text/html;charset=utf-8");

        }

 

        Transport.send(msg); // send mail

    }

 

    // 메시지를 생성한다.

    private Message createMessage(String authId, String authPasswd,

            String from, String fromName, String[] to, String[] cc,

            String[] bcc, File[] attachFiles) throws Exception {

        GmailSmtpAuthenticator auth = new GmailSmtpAuthenticator(authId,

                authPasswd); 

        Session mailSession = Session.getDefaultInstance(props, auth);

 

        // create message

        Message msg = new MimeMessage(mailSession);

 

        if (fromName != null) {

            msg.setFrom(new InternetAddress(from, MimeUtility.encodeText(

                    fromName, "UTF-8", "B")));

        } else {

            msg.setFrom(new InternetAddress(from));

        }

 

        // add to

        InternetAddress[] toAddr = null;

        if (to != null) {

            toAddr = new InternetAddress[to.length];

            for (int i = 0; i < to.length; i++) {

                toAddr[i] = new InternetAddress(to[i]);

            }

        } else {

            toAddr = new InternetAddress[1];

            toAddr[0] = new InternetAddress(authId);

        }

        msg.setRecipients(Message.RecipientType.TO, toAddr);

 

        // add cc (참조)

        if (cc != null) {

            InternetAddress[] ccAddr = new InternetAddress[cc.length];

            for (int i = 0; i < cc.length; i++) {

                ccAddr[i] = new InternetAddress(cc[i]);

            }

 

            msg.setRecipients(Message.RecipientType.CC, ccAddr);

        }

 

        // add bcc (숨은참조)

        if (bcc != null) {

            InternetAddress[] bccAddr = new InternetAddress[bcc.length];

            for (int i = 0; i < bcc.length; i++) {

                bccAddr[i] = new InternetAddress(bcc[i]);

            }

 

            msg.setRecipients(Message.RecipientType.BCC, bccAddr);

        }

 

        if (attachFiles != null) {

            // 파일 첨부

            Multipart multipart = new MimeMultipart();

 

            for (File attachFile : attachFiles) {

                if (attachFile != null && attachFile.exists()) {

                    MimeBodyPart mimeBodyPart = new MimeBodyPart();

 

                    mimeBodyPart.setDataHandler(new DataHandler(

                            new FileDataSource(attachFile)));

                    mimeBodyPart.setFileName(attachFile.getName());

 

                    multipart.addBodyPart(mimeBodyPart);

                }

            }

 

            msg.setContent(multipart);

        }

 

        return msg;

    }

 

    private static class GmailSmtpAuthenticator extends Authenticator {

 

        private String id = null;

        private String passwd = null;

 

        public GmailSmtpAuthenticator(String id, String passwd) {

            this.id = id;

            this.passwd = passwd;

        }

 

        @Override

        protected PasswordAuthentication getPasswordAuthentication() {

            return new PasswordAuthentication(id, passwd);

        }
    }
 

            

}

Java Mail의 mail.jar가 패스에 잡혀 있어야 한다.

Posted by as.wind.914
Mobile Dev/Android2010. 12. 16. 20:04
특정 안드로이드 어플에서 티스토어의 어플 페이지로 링크를 하는 방법이다.
웹 브라우저를 통해서 링크를 할 수도 있지만, 여기서는 티스토어 어플을 실행하고 티스토어 어플에서 해당 PID의 어플 페이지를 보여주는 방법이다.

String tstorePID = "0000056482";
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setClassName("com.skt.skaf.A000Z00040", "com.skt.skaf.A000Z00040.A000Z00040");
intent.setAction("COLLAB_ACTION");
intent.putExtra("com.skt.skaf.COL.URI", ("PRODUCT_VIEW/" + tstorePID + "/0").getBytes());
intent.putExtra("com.skt.skaf.COL.REQUESTER", "A000Z00040"); // tstore app ID
activity.startActivity(newintent);

위와 같이 Intent Call을 하게 되면 단말에 설치 된 티스토어 어플이 실행이되고, 해당 PID의 앱 설명 페이지가 나오게 된다. 물론 단말에 티스토어 어플이 설치되어 있어야 한다.
Posted by as.wind.914
Mobile Dev/Android2010. 11. 30. 11:22
모바일 앱을 만들다보면 의외로 Shorten URL이 많이 필요하게 된다.
Shorten URL을 공짜로 서비스하며 그 중에서 API를 제공하는 사이트도 다수가 있다.
그중에서 가장 많이 사용하는 bit.ly 사이트의 API를 이용하여 Shorten URL을 연동하는 방법을 알아본다.

참고로 code.google.com에서 bit.ly로 검색해보면 오픈된 프로젝트가 있으나, 난 그냥 Shorten URL을 연동하는 것만 만들어서 사용했다.

1. 인증
bit.ly의 API를 사용하기 위해서는 bit.ly의 계정과 api key가 필요하다.

1. bit.ly에 계정을 생성한다. 계정이 존재한다면 그냥 사용해도 된다. (http://bit.ly/a/sign_up)
2. bit.ly 사이트에 로그인하고 사용할 개인 api key를 발급 받는다. (http://bit.ly/a/your_api_key)

이 두단계면 인증절차를 위한 준비는 완료이다. 또, bit.ly에 계정을 만들면 자신이 생성한 Shorten URL에 대한 히스토리를 확인 할 수도 있다.

2. Shorten URL 연동
Shorten URL을 연동하기 위한 방법으로 api url을 직접 호출하여 결과를 얻어오는 방식을 이용한다.
결과에 대한 포맷은 여러가지가 존재하지만 XML 포맷을 선택했다.

연동 절차는 아주 간단하다.
1. Shorten URL을 제공하는 api url을 호출한다. (요청 파라미터 포함)
2. 응답 XML을 파싱한다.

API URL : http://api.bit.ly/v3/shorten
Request Parameter
    - login : 인증 할 계정 아이디
    - apiKey : 계정으로 발급 받은 개인 api key 값
    - format : 응답 포맷
    - longUrl : Shorten URL로 변환 할 Long URL (URLEncoder 해서 사용한다.)
물론 Get/Post 둘다 가능하다.
예) http://api.bit.ly/v3/shorten?login=[아이디]&apiKey=[개인 api key]&format=[응답 포맷]&longUrl=[원본 URL]

Shorten URL 연동 결과 XML 
<?xml version="1.0" encoding="utf-8" ?> 
<response>
    <status_code>200</status_code> 
    <status_txt>OK</status_txt> 
    <data>
        <url>http://bit.ly/i35TSJ</url> 
        <hash>i35TSJ</hash> 
        <global_hash>3GtD5m</global_hash> 
        <long_url>http://www.naver.com</long_url> 
        <new_hash>0</new_hash> 
    </data>
</response>

API 연동 부분 (HttpClient의 Get 방식을 이용)
public String getShortUrl(String longUrl) throws Exception {
  String shortUrl = null;

  HttpClient httpClient = null;
  try {
     httpClient = new HttpClient();

     StringBuilder bitlyUrl = new StringBuilder("http://api.bit.ly/v3/shorten"));
     bitlyUrl.append("?");
     bitlyUrl.append("login").append("=").append("ukzzang").append("&");
     bitlyUrl.append("apiKey").append("=").append("xxxxxxxxxxxxxxx").append("&");
     bitlyUrl.append("format").append("=").append("xml").append("&");
     bitlyUrl.append("longUrl").append("=").append(URLEncoder.encode(longUrl));

     InputStream in = null;
     try {
        in = httpClient.requestGet(bitlyUrl.toString()); // api call (get method)

        BitLyResponseParser parser = new BitLyResponseParser();
        BitLyResultInfo resultInfo = parser.parseXml(in, "utf-8"); // 응답 XML 파싱

        if (resultInfo.getStatusCode() == 200) {
           shortUrl = resultInfo.getUrl();
        } else {
           throw new Exception(resultInfo.getStatusCode() + ":" + resultInfo.getStatusTxt());
        }
     } finally {
        if (in != null) {
           in.close();
           in = null;
        }
     }
  } finally {
     if (httpClient != null) {
        httpClient.shutdown();
        httpClient = null;
     }
  }

  return shortUrl;
}

응답 XML을 파싱하는 Parser
// bit.ly response xml parser
private class BitLyResponseParser extends ApiXmlParser {
  public BitLyResponseParser() throws XmlPullParserException {
     super();
  }

  @Override
  public BitLyResultInfo parseXml(InputStream inputStream,
        String inputEncoding) throws Exception {
     BitLyResultInfo resultInfo = null;

     parser.setInput(inputStream, inputEncoding);
     int mParserEvent = parser.getEventType();
     String mTag = null;

     while (mParserEvent != XmlPullParser.END_DOCUMENT) {
        switch (mParserEvent) {
         case XmlPullParser.START_TAG:
            mTag = parser.getName();

            if ("response".compareTo(mTag) == 0) {
               if (resultInfo == null) {
                  resultInfo = new BitLyResultInfo();
               }
            } else if ("status_code".compareTo(mTag) == 0) {
              resultInfo.setStatusCode(Integer.parseInt(parser .nextText()));
            } else if ("status_txt".compareTo(mTag) == 0) {
               resultInfo.setStatusTxt(parser.nextText());
            } else if ("url".compareTo(mTag) == 0) {
               resultInfo.setUrl(parser.nextText());
            } else if ("hash".compareTo(mTag) == 0) {
               resultInfo.setHash(parser.nextText());
            } else if ("global_hash".compareTo(mTag) == 0) {
               resultInfo.setGlobalHash(parser.nextText());
            } else if ("long_url".compareTo(mTag) == 0) {
              resultInfo.setLongUrl(parser.nextText());
            }

            break;
         }

         mParserEvent = parser.next();
      }

      return resultInfo;
   }
}

public class BitLyResultInfo {
  private int statusCode = 200; // status code (200 성공)
 
private String statusTxt = null; // status text

 
private String url = null; // short url
 
private String hash = null; // hash
 
private String globalHash = null; // global hash
 
private String longUrl = null; // original long url

  // ******************** 아래에 getter and setter method 명시
}

위의 소스를 이용하면 손쉽게 bit.ly의 Shorten URL을 연동할 수 있다.
Posted by as.wind.914