반응형

g4j - GMail API for Java

GMailer API for Java (g4j) is set of API that allows Java programmer to communicate to GMail. With G4J programmers can made Java based application that based on huge storage of GMail.

An Email application, GMailer for Java is also built to demonstrate the usage of the API. It is planned to include minimalist email capabilities such as browse, search, read, send mail and download attachment.

This software is distributed in GNU General Public Lincense (GPL).

Download

The g4j package includes the library, the Email application and javadocs. The g4j-deps package is required if you want to compile g4j. Current version of API is 0.3.12 and Email application is 0.3.4.

For latest source code you can Browse CVS Repository or get the CVS by:

cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/g4j login

cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/g4j co src

Check the project statistics, woo we've made 10000+ lines of code in a month!

Release Notes 0.3.12

G4J finally support the new contact list interface! (read only)

Matthias fix bug in GMailer that scroll the message to bottom. He have also added open browser function, the links in messages now clickable!

You would need Java Runtime Environment (JRE) to run this software, download it in http://java.sun.com/

To use the software, run g4j.bat on Windows or g4j.sh on Unix. To Use the library include the g4j-lib.jar in your programs.

If you encounter error message: "sun.security.validator.ValidatorException: No trusted certificate found" while connecting gmail, please read the solution.

This program is developed mainly in Windows XP & 2000, it have not been tested on other platforms. If you encounter any problem please post a message in project support page.

G4J

Set of API that allows Java programmer to communicate to GMail. API is avaliable online.

  • Version 0.3.11 - (15-Oct-2004)
    Fixed: Support the new gmail contact interface, GMContact structure changed, new function GMConnector.getContact() replace old requestContact()
  • Version 0.3.10 - (7-Oct-2004)
    Added: GMConnector.fetchOriginalMail(String id) added, download original mail source from gmail
    Added: Preliminary support of send mail.
    Bugfix: "Drafts" mail now being prased correctly
  • Version 0.3.9 (5-Oct-2004)
    Update: GMail new mailbox "Drafts" supported
  • Version 0.3.4 (27-Sep-2004)
    Features: With multi-threaded http client, single connector can send multiple request at the same time
    Features: Parse the java script redirection in request()
  • Version 0.3.3 (22-Sep-2004)
    Bug Fix: Correctly parse escaped characters such as ' " < > \n and \r;
    Features: Implement missing "message body" packets in entries in conversation
  • Version 0.3 (18-Sep-2004)
    API to download conversation and open attachment as InputStream
  • Version 0.2
    API to retrive threads from mailbox/label and search message
  • Version 0.1
    API to connect to GMail

GMailer for Java

Minimalist Email client that retive email from Gmail.

Features:

  • Check and monitor mailboxes
  • Read mail
  • Search mail
  • Minimized to SysTray in Windows and Linux KDE3
  • Message saved to local disk and can be read later offline
  • Version 0.3.4
    (16-Oct-2004)
    Added: Open gmail home page (like original gmail notifier)
    Added: Open links in message
    Bugfix: Scroll to buttom when open a message
  • Version 0.3.3
    (15-Oct-2004)
    Added: Search messages
    Bugfix: Show offline message list correctly
    Bugfix: Click the sys tray icon before the program completely loaded, the program would popup and behave strangly
    Enhance: new toolbar buttons for better looks, across different platform/LAF
  • Version 0.3.2
    (7-Oct-2004)
    Added: Debug console
    Bugfix: Fix the problem that when exit without login, the software might not exiting properly.
    Bugfix: "Drafts" mail now being displayed correctly
  • Version 0.3.1
    (5-Oct-2004)
    Update: GMail new mailbox "Drafts" supported
  • Version 0.3 (3-Oct-2004)
    - BUGFIX: Reformat the message pane so that user can use mouse wheel to scroll message content.
    - ENHANCEMENT: improved performance to apply a LAF
  • Version 0.3-pre3 (1-Oct-2004)
    - FEATURES: Look and Feel chooser avaliable in option, features JGoodies Look and feel and theme
    - ENHANCEMENT: Show or hide message content using a better method, preformance improved
    - BUGFIX: Correctly disable menu items/toolbar buttons
  • Version 0.3-pre2 (27-Sep-2004)
    If a message is already downloaded, now GMailer read message from local disk instead of download again
    With multi-threaded g4j api and rewritten usage of threads, the general performance is improved
    Correct the tooltips of the systray icon
  • Version 0.3-pre1 (26-Sep-2004)
    Save data to local drive, the programs now can work offline to read downloaded message.
    Rewrite UI, now looks more comfortable. Add serveral icons, partly from Eclipse and others are draw by me.
  • Version 0.21 (22-Sep-2004)
    Open message body (partly)
  • Version 0.2 (18-Sep-2004)
    Added support of minimized to SysTray in Windows and KDE3; Support of auto connect and check message and various UI fix (18-Sep-2004)
  • Version 0.1
    This version connect to GMail and listing mailboxes. Searching, Viewing email and download attachment would be included in future release.

Acknowledgement

This project is inspried and motivated by GMailer for PHP and Gmail Agent API , their great works make me want to have an Java Implementation of their kind. Their open sources also made the understanding of GMail's protocol much easier, Thank You!

This project is not possible without following open source softwares:

  • Apache Jakarta Commons HTTPClient to access web page
  • Apache Jakrata Commons Codec to decode email
  • SysTray for Java to make the System Tray tricks
  • SIXBS (Simple XML Bean Serialization) from tagtraum industries, for saving document in XML
  • JGoodies for better UI looks
  • Concurrent Utilities from Doug Lea
  • BeanShell for embbed scripting engine
  • Eclipse for their nice icons
  • Google for their GMail, of course

Support and Contribution

If you have any problem, opinion, or software that built on g4j, please tell me via email or Sourceforge Forum!

Thanks Teodor and Samanth to join this project! They would help me to make GMailer more usable and I can focus more on the G4J API.

If you can join us, send me an email. You can also browse the todo list and give us suggestions!

Related Projects

  • Rishabh made gavamail , a POP3 inetrface for gmail in Java

About Me

I am a tiny programmer in a big enterprise in Hong Kong.

Read my blog in www.siuying.net ( Chinese Content )

[출처] g4j - GMail API for Java|작성자 후니


반응형
About the Browser

This section explains the architecture of Microsoft Internet Explorer 4.0 and later and provides information you will find helpful when reusing these components.

This topic contains the following sections.

Architectural Overview

Windows Internet Explorer uses Microsoft ActiveX Controls and Active Document interfaces to connect components. The following diagram provides a high-level overview.

Internet Explorer 4.0 Architecture.

IExplore.exe is at the top level; it is a small application that is instantiated when Internet Explorer is loaded. This executable application uses Internet Explorer components to perform the navigation, history maintenance, favorites maintenance, HTML parsing and rendering, and so on, while it supplies the toolbar and frame for the stand-alone browser. IExplorer.exe directly hosts the Shdocvw.dll component.

Shdocvw.dll in turn hosts the Mshtml.dll component, as well as any other Active Document component (such as a Microsoft Office application) that can be loaded in place in the browser when the user navigates to a specific document type. Shdocvw.dll supplies the functionality associated with navigation, in-place linking, favorites and history management, and PICS support. This DLL also exposes interfaces to its host to allow it to be hosted separately as an ActiveX control. The Shdocvw.dll component is more frequently referred to as the WebBrowser Control. In-place linking refers to the ability to click a link in the HTML of the loaded document and to load a new HTML document in the same instance of the WebBrowser Control. If only Mshtml.dll is being hosted, a click on the link results in a new instance of the browser.

Mshtml.dll is the component that performs the HTML parsing and rendering in Internet Explorer 4.0 and later, and it also exposes the HTML document through the Dynamic HTML Object Model. This component hosts the scripting engines, Microsoft virtual machine, ActiveX Controls, plug-ins, and other objects that might be referenced in the loaded HTML document. Mshtml.dll implements the Active Document server interfaces, which allows it to be hosted using standard Component Object Model (COM) interfaces.

As this is an OLE-based architecture, the ambient properties that are commonly used by ActiveX Controls can also be applied to the Internet Explorer components. In this way, a host of the WebBrowser Control can set an ambient property that will filter down to all the frames and controls hosted in the loaded document.

Choosing the Correct Component

The WebBrowser Control provides a rich set of functionality that a host typically requires, such as that for in-place linking. Therefore, it is much more applicable for most applications to host this control instead of MSHTML for browsing or viewing HTML documents. Hosting MSHTML is recommended only for specialized applications, such as parsing HTML. The WalkAll Sample Source Page demonstrates how to host MSHTML.

It should also be noted that although hosting MSHTML is slightly more lightweight than hosting the WebBrowser Control, the savings rarely justify the extra work involved in implementing functionality that is already available in the WebBrowser Control. It is very likely that the WebBrowser Control will already be loaded in memory, and navigating to a frameset page will also result in the WebBrowser Control being loaded as part of the standard working set.

Providing Extra Control

Hosts of the WebBrowser Control and MSHTML components have control over certain functionality. In the case of the WebBrowser Control, this includes navigation, as well as receiving events when the document is loaded. Hosts of either component can obtain extra control over functionality by implementing the IDocHostUIHandler and IDocHostShowUI interfaces. These interfaces are commonly used to override the context menus that are supplied by default for the browser. Their uses also include setting the 3-D border, overriding the location in the registry where options are stored, and extending the Dynamic HTML Object Model.

The component obtains these interfaces from the host by calling QueryInterface on the IOleClientSite interface implemented by the hosting application.

Controlling the Context Menus

A common requirement of hosting the WebBrowser Control is the ability to override or add to the context menus that are displayed as the result of a right-click in the browser window. This is of particular interest to applications that are using the WebBrowser Control to view rich content but do not want the user to know that HTML is being viewed. This is also advantageous for applications that do not want the user to be able to view the HTML source for the content.

There are two techniques available to achieve this. The first involves the use of the IDocHostUIHandler interface and allows an application to disable or replace the context menus. The second technique involves the use of the registry and allows the existing context menus to be extended.

Overriding the Context Menus

The WebBrowser Control's context menus can be overridden entirely by implementing the IDocHostUIHandler::ShowContextMenu method. Returning E_NOTIMPL or S_FALSE from this method indicates to the WebBrowser Control that it should display its own standard context menu. However, returning S_OK causes the WebBrowser Control not to display its menus, and it assumes that the host has performed the appropriate action. The host can disable all context menus or bring up its own context menus. The parameters supplied to the host that implements this method allow that host to identify which of the default menus will be displayed by the WebBrowser Control, as well as the coordinates where the menu will be displayed. This provides the host the full context for the menu. For example, the host can choose to override only the image context menus and not the standard context menus.

Adding to the Standard Context Menus

Items can be added to the existing context menus of the WebBrowser Control by placing entries in the registry and linking these to URLs that execute script. To add items to the standard WebBrowser Control context menus, create or open the following key:

  • HKEY_CURRENT_USER
    • Software
      • Microsoft
        • Internet Explorer
          • MenuExt

Under this key, you create a key whose name contains the text you want displayed in the menu. The default value for this key contains the URL that will be executed. The key name can include the ampersand (&) character, which will cause the character immediately following the & to be underlined. The URL will be loaded inside a hidden HTML dialog box, all the inline script will be executed, and the dialog box will be closed. The hidden HTML dialog's menuArguments property (on the external object) contains the window object of the window on which the context menu item was executed.

The following registry entry adds an item with the title "My Menu Item" to the WebBrowser Control context menu and executes the inline script contained in the file c:\myscript.htm.

  • HKEY_CURRENT_USER
    • Software
      • Microsoft
        • Internet Explorer
          • MenuExt
            • My &Menu Item

            • (Default) = file://c:\myscript.htm

The contents of c:\myscript.htm are as follows:

<SCRIPT LANGUAGE="JavaScript" defer>
   var parentwin = external.menuArguments;
   var doc = parentwin.document;
   var sel = doc.selection;
   var rng = sel.createRange();
   var str = new String(rng.text);

   if(str.length == 0)
      rng.text = "MY INSERTED TEXT";
   else
      rng.text =  str.toUpperCase();
</SCRIPT>

This script obtains the parent window object from external.menuArguments. The parent window object is the WebBrowser Control in which the context menu item was executed. The script then obtains the current selection and, if no selection is present, inserts the text "MY INSERTED TEXT" at the point where the context menu was executed. If there is a selection present, the selected text is changed to uppercase.

Optional keys

Under the item registry key created earlier, there are a couple of optional values. One of these specifies on which context menus this item will appear. The other specifies that the script should be run as a dialog box.

The "Contexts" DWORD value specifies the context menus in which an item will appear. This value is a bit mask consisting of the logical OR of the following values (defined in Mshtmhst.h). These values correspond to the constant passed in an IDocHostUIHandler::ShowContextMenu call.

Value Constant Name Description
0x01 CONTEXT_MENU_DEFAULT Shown on all context menus.
0x02 CONTEXT_MENU_IMAGE Context menu of images only.
0x04 CONTEXT_MENU_CONTROL Context menu of form controls only.
0x08 CONTEXT_MENU_TABLE Context menu of tables only.
0x10 CONTEXT_MENU_TEXTSELECT Context menu of selected text only, including images in a selected region.
0x20 CONTEXT_MENU_ANCHOR Context menu of links only. Does not include linked images or image maps.
0x40 CONTEXT_MENU_UNKNOWN Right-click on none of the above.

So if, for example, you want this simple extension to appear only in the default menu and the text selection menu, you could create a DWORD value in the registry under the My Menu Item key called "Contexts" and set it to 0x11. From C/C++ code, this can be expressed as:

CONTEXT_MENU_DEFAULT | CONTEXT_MENU_TEXTSELECT

The other optional registry DWORD value is "Flags". There is only one valid bit (0x1) for this registry value; it is defined as MENUEXT_SHOWDIALOG in Mshtmhst.h. When this bit is set, the script is run just as if it had been called through the IHTMLWindow2::showModalDialog method. The window that runs the script is not hidden, and the dialog box is not automatically closed after inline and onload script finishes. The external.menuArguments value still contains the window object where the user selected the menu item.

The context menu event

Whenever a context menu extension is triggered, the event object off the main window (external.menuArguments.event) contains information about where the user clicked and which context menu was shown. The mouse coordinates are valid along with srcElement. The type value contains one of the following strings, indicating which context menu was shown to the user:

  • MenuExtDefault
  • MenuExtImage
  • MenuExtControl
  • MenuExtTable
  • MenuExtTextSelect
  • MenuExtAnchor
  • MenuExtUnknown

Another example

This example creates a new menu item on the default context menu. This item, called Show In New Window, can be used to launch a new window that displays only a specific portion of the current document. If something is deeply nested in a frameset, you can easily launch a specific frame in its own window.

Here are the contents of a .reg file that can be run to insert the correct registry settings. Call this file Example2.reg. Double-clicking this file in Windows Explorer will insert the settings in your registry.

REGEDIT4

    [HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Show in New Window]
    @="file://c:\\example2.htm"
    "Contexts"=dword:00000001

Here are the contents of c:\example2.htm:

<SCRIPT LANGUAGE="JavaScript" defer>
    window.open(external.menuArguments.location.href);
</SCRIPT>

For more information, see Adding Entries to the Standard Context Menu.

Extending the Dynamic HTML Object Model

It is possible for the hosting application to extend the Dynamic HTML Object Model so that scripts can refer to functionality implemented by the host. Such scripts refer to the host by specifying the external object that is available from the window object. For example, a reference to "window.external.speech" will call the host to resolve the name "speech." All standard script within the document will be executed normally.

This extension mechanism is implemented in the host by providing an IDispatch interface for the object model extension that will have IDispatch::GetIDsOfNames and IDispatch::Invoke called on it to resolve any references to the external object. The IDispatch that the host provides is obtained by the WebBrowser Control or MSHTML component by calling the host's IDocHostUIHandler::GetExternal method.

For an example of how to extend the Dynamic HTML Object Model, see the Driller Sample Source Page.

Download Control

Hosts can control certain aspects of downloading—frames, images, Java, and so on—by implementing both IOleClientSite and an ambient property defined as DISPID_AMBIENT_DLCONTROL. When the host's IDispatch::Invoke method is called with dispidMember set to DISPID_AMBIENT_DLCONTROL, it should place zero or a combination of the following values in pvarResult.

DLCTL_BGSOUNDS The browsing component will play background sounds associated with the document.
DLCTL_DLIMAGES The browsing component will download images from the server.
DLCTL_DOWNLOADONLY The browsing component will download the page but not display it.
DLCTL_FORCEOFFLINE The browsing component will always operate in offline mode. This causes the BINDF_OFFLINEOPERATION flag to be set even if the computer is connected to the Internet when making requests through URLMON.
DLCTL_NO_BEHAVIORS The browsing component will not execute any behaviors.
DLCTL_NO_CLIENTPULL The browsing component will not perform any client pull operations.
DLCTL_NO_DLACTIVEXCTLS The browsing component will not download any ActiveX Controls in the document.
DLCTL_NO_FRAMEDOWNLOAD The browsing component will not download frames but will download and parse the frameset page. The browsing component will also ignore the frameset, and will render no frame tags.
DLCTL_NO_JAVA The browsing component will not execute any Java applets.
DLCTL_NO_METACHARSET The browsing component will suppress HTML Character Sets reflected by meta elements in the document.
DLCTL_NO_RUNACTIVEXCTLS The browsing component will not execute any ActiveX Controls in the document.
DLCTL_NO_SCRIPTS The browsing component will not execute any scripts.
DLCTL_OFFLINE Same as DLCTL_OFFLINEIFNOTCONNECTED.
DLCTL_OFFLINEIFNOTCONNECTED The browsing component will operate in offline mode if not connected to the Internet. This causes the BINDF_GETFROMCACHE_IF_NET_FAIL flag to be set if the computer is connected to the Internet when making requests through URLMON.
DLCTL_PRAGMA_NO_CACHE The browsing component will force the request through to the server and ignore the proxy, even if the proxy indicates that the data is up to date. This causes the BINDF_PRAGMA_NO_CACHE flag to be set when making requests through URLMON.
DLCTL_RESYNCHRONIZE The browsing component will ignore what is in the cache and ask the server for updated information. The cached information will be used if the server indicates that the cached information is up to date. This causes the BINDF_RESYNCHRONIZE flag to be set when making requests through URLMON.
DLCTL_SILENT The browsing component will not display any user interface. This causes the BINDF_SILENTOPERATION flag to be set when making requests through URLMON.
DLCTL_URL_ENCODING_DISABLE_UTF8 The browsing component will disable UTF-8 encoding.
DLCTL_URL_ENCODING_ENABLE_UTF8 The browsing component will enable UTF-8 encoding.
DLCTL_VIDEOS The browsing component will play any video clips that are contained in the document.

Security Manager

Hosts of the browsing components can implement their own security management and override the settings that exist for the WebBrowser Control. This is achieved by implementing the IInternetSecurityManager interface. The browsing component will obtain this interface by calling the host's IServiceProvider::QueryService method with SID_SInternetSecurityManager. For more information on security management, see About URL Security Zones.


반응형

Java 로 사용될 수 있는 Browser Component 에 대하여 (리눅스 플렛폼에서 사용할 목적으로) 조사하였음.

실 사용자의 사용 브라우저와 가장 근접한 렌더링 결과를 내면서 가장 높은 접근성을 가지는 것을 목적으로 조사하였기 때문에.

결과가 Mozilla Compatable 한 방향으로 편중 되어 있음을 미리 염두에 두고 보시면 편할 듯.


http://www.webrenderer.com/index.php

Full Swing 으로 구현된 Mozilla Compatable Browser. 상용이다.

아무래도 돈주고 사는 제품이다 보니, 완성도는 높을 듯. 랜더링,접근성 대비 최상이라고 예상됨.


http://www.icesoft.com/products/icebrowser.html

Full Java로 구현되었으며 Java Application에 Embed 되어 사용되는 목적으로 개발 되었다.

상용제품으로 완성도는 높지만, 가격이 문제. Mozilla Compatable 하지 않으므로 효용성이 떨어짐


http://jazilla.sourceforge.net/

Java로 구현된 Mozilla compatible(HTML,XUL) rendering engine

현재 M4 까지 진행 된 상태 이며, 오픈소스로 진행 되며, M4까지 진행 된 관계로 완성도가 떨어질 것으로 예상.

정확한 완성도는 살펴보지 못 하였음. 관련 자료는 http://sourceforge.net/projects/jazilla/ 에서 다운로드 받을 수 있음.


http://mozillaparser.sourceforge.net/

Mozilla Parser만 연결한 방식, Rendering 이 들어가 있지 않으므로 반쪽 효용성.

JNI 방식이며 설명에도 나와 있지만 연결방식이 매끄럽지 못하여 성능 문제가 있는것 으로 보임.


http://www.eclipse.org/atf/

가장 Stable 하다는 평이 있음. SWT 용 이며, Browser 목적으로 따로 나와 있는 것이 아니고,

ATF에서 사용되는 일부 기능인 만큼, 분석 및 따로 떼어서 작성하는 과정이 필요함. (Firefox,IE 등 모두 연결 가능)


http://www.mozilla.org/projects/blackwood/webclient/

Java WebShell 을 사용하는 개념을 지원하는 Mozilla 프로젝트 (Gecko 뿥만 아니라 Windows에서 IE도 연결 가능하다고 함)

Mozilla 정식 프로젝트 인 만큼 가장 많은 기능을 사용할 수 있으며, 랜더링 또한 Firefox와 같은 수준

접근성 또한 높은 수준으로 제공됨, 다만 Full Java 가 아니기 때문에 완벽한 접근성이 보장되는 것은 아님.


https://jdic.dev.java.net/

java.net 에서 호스트 되는 프로젝트로 Mozilla 뿐만 아니라 IE등의 브라우져를 JNI 방식으로 연결하여 제공한다.

기능성 및 접근성이 많이 떨어진다.


http://jrex.mozdev.org/

Mozilla Gecko를 Embedding 하여 사용할 수 있도록 지원한다. JNI 방식이며 GRE를 설치하여 사용한다.

Mozilla Gecko 1.4  이상 과 호환되며 접근성은 어느정도 제한적 인 것으로 보인다.

반응형
V. 메일 수신 예제
=================

 이 장에서는 JavaMail API를 이용한 메시지 수신 예제인 MailReciever.java에 대하여 다루겠다.
MailReciever는 간단하게 POP3를 이용하여 수신함에서 메일 메시지를 가져다가 local disk에
저장하는 프로그램이다.  전체 코드는 MailReciever.java 화일로 첨부해놓았으며, 여기서는
주로 전체적인 기능 및 부분 코드로 설명하겠다.

  MailReciever를 실행 시키려면 우선 다음과 같이 메일 호스트, 사용자 아이디, 암호 그리고
메일을 저장할 디렉토리이름을 main 메소드 에서 변경하여 바꾼 후에 컴파일 하여 실행 시키면 된다.

MailReciever reciever = new MailReciever();
reciever.setHost("www.xxxx.yyyy");
reciever.setUser("aaaa");
reciever.setPassword("bbbb");
reciever.setHomeDir("c:/mail");
        
reciever.recieve();


1. constructor
-----------------------------------------

  MailReciever의 Constructor에서는 우선 다음과 같이 메일 처리를 위한 Session 객체를 
생성하고 있다. Session 객체는 member variable인 session에 대입하여 놓는다.

Properties props = System.getProperties();
session = Session.getDefaultInstance(props, null);


2. recieve()
-----------------------------------------
  실제 메일을 수신하는 메소드는 recieve() 메소드 이다.  recieve() 메소드는 session으로 부터
pop3 Store 객체를 생하고 INBOX folder를 생성하여 message를 수신한다.

......

// Get folder
Folder folder = store.getFolder("INBOX");
    
// Open read-write
folder.open(Folder.READ_WRITE);
    
// Get message
Message message[] = folder.getMessages();
......

메일을 목록을 저장할 index화일과 메시지들을 저장할 디렉토리를 생성한 후에 
각각의 메시지들을 processMessage() 메소드를 호출하여 처리한다.

// index open
File indexFile = File.createTempFile("list", ".idx", new File(getHomeDir()));
FileOutputStream fout = new FileOutputStream(indexFile.getPath(), true);
indexWriter = new BufferedWriter(new OutputStreamWriter(fout));
        
// make folder
mailFolderName = getHomeDir() + "/" + indexFile.getName() + ".dir";
File mailFolder = new File(mailFolderName);
mailFolder.mkdir();
        
// process message
for(int i=0; i < message.length; i++) {
    processMessage(message[i]);
}

.......


3. processMessage()
---------------------------------------
  processMessage() 메소드는 각각의 메시지에 대한 발신자, 제목, 발신일, 저장할 폴더 등
목록에 해당하는 내용을 만든다.

.............

 // from
 sarr = message.getHeader("From");
 if(sarr == null || sarr.length == 0) {
   from = "";
 }
 else {
  from = decodeString(sarr[0]);
 }
            
 // subject
 sarr = message.getHeader("Subject");
 if(sarr == null || sarr.length == 0) {
   subject = "";
 }
 else {
   subject = decodeString(sarr[0]);
  }
            
// send date
sendDate = message.getSentDate();

.................


  메시지의 내용을 저장할 message+msgIndex 디렉토리를 만든다.  메시지의 내용과 
첨부 화일을 저장해야 함으로 내용을 저장할 $content.message 화일은 미리 open해 놓는다.
message는 여러부분의 Part로 구성될 수 있으므로 processPart 메소드를 호출하여 처리한다.
메시지를 처리한 후에 index 부분을 write한다.

        
// open content writer
FileOutputStream fout = new FileOutputStream(msgFolderName + "/" + "$content.message");
contentWriter = new BufferedWriter(new OutputStreamWriter(fout));
        
//process part
System.out.println(message.getSubject());
processPart(message);        
        
// header white
indexWriter.write(from + "\t");
indexWriter.write(subject + "\t");
indexWriter.write(sendDate +"\t");
indexWriter.write(msgFolderName + "\t");
indexWriter.write(appendCount + "\n");

// close content writer
contentWriter.close();


4. processPart()
--------------------------------------
  processPart()는 우선 Part의 내용을 화일로 저장할지 아니면 메시지 내용으로 write할 지를
결정한다.

String fileName = part.getFileName();
String disposition = part.getDisposition();
boolean isAttachement = false;
        
if (fileName != null || disposition != null) {
  isAttachement = true;
}

......

  mime type에 따라 Part의 내용을 처리하되 "text/*" 일 경우는 내용 저장, "multipart/*" 일 경우는
이를 다시 Part로 나누어 재귀적으로 processPart() 메소드를 호출, 그리고 "message/rfc822" 일 경우는
다시 processPart()를 다시 호출 한다.  나머지 경우는 내용을 저장한다.


if (part.isMimeType("text/*")) {
    
  if(isAttachement) {
    saveFile(fileName, part.getContent());
    appendCount++;
  }
  else {
    saveContent(part.getContent());
  }
                            
} else if (part.isMimeType("multipart/*")) {
            
  Multipart mp = (Multipart)part.getContent();        
  for (int i = 0; i < mp.getCount(); i++) {
    processPart(mp.getBodyPart(i));
  }
    
} else if (part.isMimeType("message/rfc822")) {
            
  processPart((Part)part.getContent());
            
} else {
            
  Object obj = part.getContent();
        
  if(isAttachement) {
    saveFile(fileName, obj);
    appendCount++;                
  }
  else {
    saveContent(obj);
  }

}


5. saveFile()
--------------------------------------
  화일이름과 내용을 담은 Object를 주면 중복되지않게 화일 이름에 일련번호를 붙여
내용을 저장한다.  내용 Object 가 InputStream일 경우는 stream을 읽어 내용을 저장하고
아닐 경우는 String으로 만들어 저장한다.


6. saveContent()
--------------------------------------
  내용을 담은 Object를 받아들여 이미 열려있는 contentWriter에 내용을 write한다.
내용 Object 가 InputStream일 경우는 stream을 읽어 내용을 저장하고
아닐 경우는 String으로 만들어 저장한다.


7. 기타 methods
--------------------------------------
  toHangle 메소드는 문자열을 한글체계로 바꾸는 메소드이고, decodeString은
메일 메시지의 헤데 문자열이 encoding되어 있을 때 MimeUtility를 이용하여
decode 하는 메소드이다.  searchPattern은 encoding되어 있는 문자열을 구분해내는
역할을 한다. 
반응형
IV. 메일 메시지 수신
======================

  메일 메시지의 수신은 우선 POP3나 IMAP은 지원하는 메일 서버가 있다는 전제로
될 수 있다.  그리고 메일서버에 메일을 수신할 수 있는 계정이 만들어져있고
수신함 즉 "INBOX"가 존재하여 타인이 메일 서버로 메시지를 보낼 때 이 수신함에
그 메시지가 저장이 되어야 한다. 

  이러한 환경이 설정되어 있어야 JavaMail API를 이용하여 메일 서버의 수신함에
저장된 메시지를 가져올 수 있다.  메일 서버와 통신을 하여 수신함에서 수신된 
메시지를 꺼내올 수 있는 실제 클레스들은 기본적으로 com.sun.mail.imap 과 
com.sun.mail.pop3 패키지로 제공되는데 만일 다른 제공자의 클레스를 사용하고자 
한다면 Session의 프로퍼티를 설정해야 한다.

  다음은 POP3 프로토콜을 이용하여 수신함에서 메시지를 가져와 발신자와
제목을 화면에 보여주는 예제이다.


String server = "www.xxx.zzz";
String user   = "aaaa";
String pass   = "bbbb";

// 프로퍼티 
Properties props = new Properties();

// 세션 객체 생성 
Session session = Session.getDefaultInstance(props, null);

// POP3 Store 연결
Store store = session.getStore("pop3");
store.connect(server, user, pass);

// INBOX Folder 가져옮
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);

// 수신된 메시지들을 Folder에서 가져옮
Message message[] = folder.getMessages();

for (int i=0, n=message.length; i<n; i++) {
   System.out.println(i + ": " + message[i].getFrom()[0] 
     + "\t" + message[i].getSubject());
}

// 연결을 끊는다.
folder.close(false);
store.close();
  
  위의 예에서 보듯이 POP3를 지원하는 메일 서버 주소, 아이디, 패스워드만 있으면
Stroe 객체를 통하여 서버와 연결하여 Folder객에체서 Message 객체들을 얻어와 메일을 수신할 
수 있다.  Message 객체는 메일을 구성하는 수신자, 발신자, 제목, 내용등이 모두들어
있다.

  Message객체에서 getFrom 메소드를 호출하면 발신자 경로를 추적할 수 있는 Address
Array를 받을 수 있다.  최종 발신자는 0 번째에 있다.  메일 메시지의 제목을 얻으려면
Message의 getSubject 메소드를 호출하면 된다.  이러한 수신자, 발신자 또는 제목 등은
메일은 헤더에 해당하는데, 이는 getHeader 메소드를 통하면 원본 String을 얻을 수 있다.

  String from = message.getHeader("From");
  String subject = message.getHeader("Subject");

위의 예제에서 원본 String은 MIME 규칙에 의해 Encoding되어 있는 경우가 있는데 이럴때는
java.mail.internet.MimeUtility의 decodeWord 메소드를 이용하여 원본을 복구해내야 한다.

  메시지의 내용을 받는 방법은 기본적으로 Message 클레스의 getContent 메소드를 이용하도록
되어 있다.  getContent 메소드는 Part 인터페이드에 정의 되어 있다.  하지만 메시지의
내용이 어떤형태로 구성되어 있는냐를 고려해야 한다.  

  메시지 내용의 MIME type이 "text/plain" 또는 "text/html"일 경우는 비교적 간단하게
처리할 수 있다.  getContent로 얻은 객체를 toString 메소드를 이용하여 문자열로 받을 수도
있고 또다를 방법은 getText 메소드를 이용하여 내용을 문자열로 받을 수 있다.  
내용이 어떠한 MIME TYPE을 하고 있는지는 isMimeType 메소드로 비교할 수 있다. 다음은
text로 구성된 메시지의 내용을 받은 예제이다.

  Message[] message = folder.getMessages();

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

    if(message[i].isMimetype("text/*")) {
      String content = message[i].getContent().toString();
      System.out.println(content);
    }
    else if(message[i].isMimeType("multipart/*)) {
      ...
    }
    else {
      ...
    }

  }

 메시지의 내용이 첨부화일을 갖는 경우는 보통 MIME type이 "multipart" 로 되어 있다.
이러한 경우는 Message 객체 의 content를  Multipart 객체로 casting해야 처리할 수 있다.
Multipart는 여러가지 Part가 모여있는 형태임으로 각각의 BodyPart를 추출하여 기본 내용 
텍스트로 쓸 것인지 첨부화일로 쓸 것인지를 판단한다.

Part의 내용을 처리하는 기준은 getDisposition 함수를 이용하여 얻을 수 있는데 비교할 수 있는
Constants는 Part에 있는 Part.ATTACHMENT 와 Part.INLINE이다.  Part.ATTACHMENT는 첨부
화일이라는 의미이고 Part.INLINE은 내용을 화면에 표시한다는 의미이다. 다음은 본문은
화면에 표시하고 첨부는 화일에 저장하는 예제이다.

// 메시지가 multipart인 경우
if(message.isMimeType("multipart/*")) {

  // 내용을 Multipart로 만듬
  Multipart mp = (Multipart)message.getContent();

  // 각각의 part를 순서데로 처리
  for (int i=0, n=multipart.getCount(); i<n; i++) {

    // 처리될 body part
    Part part = multipart.getBodyPart(i));

    // 처리 기준을 가져옴
    String disposition = part.getDisposition();
    String filename    = part.getFileName();
    
    // disposition이 Attachment이거나 file name이 있으면 저장
    if((disposition != null && disposition.equals(Part.ATTACHMENT)) ||
       (filename != null)) {
      saveFile(filename, part.getInputStream());
    }
    // 본문 처리
    else {
      .......
    }

  }
}

else {
  ....
}

위의 예제는 Message의 MIME type이 "multipart/*" 일 때 처리하는 로직이며
saveFile 메소드는 이미 있다고 가정한다.  그리고 본문처리 로직은
적절히 화면이 보여주거나 다른 곳이 저장한다고 가정한다.

POP3 프로토콜을 수신함에 있는 메시지를 삭제하는 기능도 정의하고 있다.
따라서 다음과 같이 수신함에 있는 메시지를 받아온 다음 수신함에서 해당 메시지를 
삭제할 수도 있다.

메시지 삭제는 다음과 같은 메시지 상태 flag를 바꾸어줌으로서 가능한데 각가의 flag는
Flags 클레스에 정의되어 있다.

- Flags.Flag.ANSWERED 
- Flags.Flag.DELETED 
- Flags.Flag.DRAFT 
- Flags.Flag.FLAGGED 
- Flags.Flag.RECENT 
- Flags.Flag.SEEN 
- Flags.Flag.USER 

위의 flag들은 모든 메일 서버가 지원하는 것은 아니다.  각각의 메일 서버마다 지원하는
flag가 있고 지원하지 않는 flag가 있다.  그리고 POP3 프로토콜에서는 DELETED flag만을
지원하도록 되어 있다. 어떠한 flag들이 지원되는지 알려면 Folder 객체의 getPermanentFlags()
메소드를 이용하면 된다.

메시지의 삭제 방법은 우선 Folder 객체를 READ/WRITE 형으로 연 다음  Message 객체의 flag을 
DELETED 상태로 바꾼다.

folder.open(Folder.READ_WRITE);
.......
message.setFlag(Flags.Flag.DELETED, true);

실제 메시지가 삭제되는 시점은 folder를 close하는 시점인데 다음과 같이 파라미터에 true를
준다.

folder.close(true);

메시지를 수신하는 전반적인 방법은 다음 장에 Reciever.java 예제로 다시한번 설명하겠다. 
반응형
III. 메일 메시지 발신
======================

  메일 메시지를 보내려면 우선 보낼 서버, 수신자, 발신자, 제목, 내용 등이 필요한다.
우선 서버의 지정은 Session을 생성할 때 넘겨주는 Properties에 "mail.smtp.host" 라는
키로 서버 주소를 지정함으로서 SMTP 전송을 처리하는 메일 서버를 지정한다.

  수신자, 발신자, 제목, 내용 등을 지정하려면 우선 이들을 하나의 메시지에 묶는
Message 객체가 필요한데, Message는 추상 클레스이므로 javax.mail.internet 패키지에
있는 MimeMessage를 이용한다.

  발신자는 Message 객체의 setFrom 메소드로 지정하되 InternetAddress 객체를 생성하여
지정한다.  수신자는 Message 객체의 addRecipient 메소드로 지정하되 Message.RecipientType
을 참고하여 지정한다.

  최종적 전송은 Transport 클레스의 static 메소드인 send로 한다.  다음은 일반 텍스트를 
SMTP를 이용하여 간단히 전송하는 예제이다.


String host = "xxx.zzz.com";
String from = "hong@xxx.zzz";
String to = "chun@aaa.bbb";

// 서버 프로퍼티 설정 
Properties props = System.getProperties();
props.put("mail.smtp.host", host);

// Session 객체 생성
Session session = Session.getDefaultInstance(props, null);

// 메시지 생성
MimeMessage message = new MimeMessage(session);
InternetAddress addr = new InternetAddress(from, "홍길동", "euc-kr");

message.setFrom(addr);
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject("Test Mail");
message.setText("This is a Test Mail");

// 메시지 전송 
Transport.send(message);


  메일 내용을 HTML로 보내려면 Message 객체의 setContent 메소드를 사용하면 된다. setContent
메소드는 Part인터페이스에 정의되어 있는데 Message 클레스는 이를 Implement하도록 되어 있다.
다음은 message 객체에 "text/html" 형식으로 내용을 주는 예제이다.


String content = "<FONT COLOR=BLUE SIZE=20> 안녕하십니까 ? " +
                 "<A HREF=WWW.JAVANURI.COM> 자바누리입니다. </A> </FONT>";
message.setContent(content, "text/html; charset=\"euc-kr\"");


  첨부 화일을 보내는 경우는 Message의 내용을 MultiPart 객체로 설정해야 한다.  MultiPart 클레스는
메시지 내용을 여러가지 부분(BodyPart)으로 구성할 수 있게 해준다.  각각의 내용부분의 BodyPart와
화일부분의 BodyPart를 생성한 후에 이들을 MultiPart에 추가하여 하나의 메시지가되도록 병합한다.
이 MultiPart를 Message의 content로 설정한 후 전송하면 여러개의 첨부화일을 간단히 처리할 수 있다.

  JavaMail API에서 화일을 처리할 경우 FileDataSource, DataHandler 등의 JAF 패키지 클레스들을
사용하게되는데 이는 JAF(JAVABEANS ACTIVATION FRAMEWORK)의 표준 자료 처리방식을 지원하는 클레스들
이다. 

  다음은 MultiPart 및 BodyPart를 구현하는 구체적 클레스 MimeMultiPart, MimeBodyPart를 이용하여
첨부 화일을 전송하는 예제이다.

SendAttachement.java
==============================================================================================
import java.io.*;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class SendAttachement {

  //-------------------------------------------
  // main
  //-------------------------------------------
  public static void main (String args[]) throws Exception {

    // 메일서버, 수신자, 발신자, 화일이름
    String host = "www.xxx.com";
    String from = "aaa@javanuri.com";
    String to = "zzz@javanuri.com";      
    String fileName = "mydoc.txt";
      
    // 프로퍼티 설정
    Properties props = new Properties();
    props.put("mail.smtp.host", host); 
  
    // Session 생성
    Session session = Session.getDefaultInstance(props, null);

    // MimeMessage 메시지 생성
    MimeMessage message = new MimeMessage(session);
    InternetAddress addr = new InternetAddress(from, "홍길동", "euc-kr");        
    message.setFrom(addr);
    message.setSubject("첨부 테스트 메일");        
    message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

    // Multi Part 생성
    Multipart multipart = new MimeMultipart();        
        
    // 메시지 BodyPart 생성 및 Mutil Part에 추가 
    BodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setText("테스트 첨부화일 입니다.");    
    multipart.addBodyPart(messageBodyPart);

    // 첨부 화일 BodyPart 생성 및 Multi Part에 추가 
    BodyPart fileBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(fileName);
    fileBodyPart.setDataHandler(new DataHandler(source));
    fileBodyPart.setFileName(fileName);
    multipart.addBodyPart(fileBodyPart);
        
    // Multi Part 메시지에 content로 설정
    message.setContent(multipart);

    // 메일 메시지 전송
    Transport.send(message);
    

  }
   
}
반응형

참고

http://java.sun.com/products/javamail/index.jsp
http://java.sun.com/javase/technologies/desktop/javabeans/glasgow/jaf.html
http://java.sun.com/developer/onlineTraining/JavaMail/contents.html

http://java.sun.com/products/javamail/javadocs/index.html
관련 시리즈
http://javacan.madvirus.net/main/search/search.tle?type=all&keyword=mail

주로 작성된 메일을 송신하고 수신하는 API를 제공하는 것이다. 이러한 기능은

메일 서버의 역할과는 구별되는 것이다.


메일 서버는 송신된 메일을 받아들이고 메일 내용을 저장하거나 재전송을 하는  Agent 역할을 한다.


JavaMail Package는 메일 서버에게 메일을 전송하고 메일 서버에 저장된 메일을 수신하는데 유용한 클레스 및 API를 제공한다.


ex) MicroSoft사의 OutLook


 JavaMail API를 구조적으로 살펴보면 우선 메시지 구성, 저장, 수신 구조를 추상화해놓은absctruct layer가 있다. 이러한 추상 계층의 목적은  특정 프로토콜과는 상관없이 메일 구조 체계를 제공하겠다는 목적이다. 즉 인터넷 메일 뿐만 아니라 모바일이나 또 다른 메일 체계에도 적용되는 구조를 제공하는 것이다.


 이러한 추상 계층 이외에 JavaMail API는 가장 흔히 사용하는 인터넷 메일을 위한 클레스 및 API를 제공한다. 이 클레스들은 기본적인 abstruct layer를 인터넷 메일이하는 측면에서 구현 즉 implementation한 클레스들이다. JavaMail API를 가지고 직접적으로 응용프로그램을 작성할 수 있는 방법은 이 인터넷 메일 구현 계층을 사용하는 것이다.


인터넷 메일에 대하여 잘 이해하려면 우선 인터넷 메일 시스템에서 사용되는 통신 프로토콜 표준에 대하여 이해할 필요가 있다. 이러한 프로토콜들은 IETF(Internet Engineering Task Force)에 의하여

소정의 절차를 거친 후 RFC라는 형태로 발표되는데 인터넷 메일과 관련된 주요 표준 프로토콜은

SMTP, POP3, IMAP, MIME 등이 있다. (http://www.ietf.org/)


- SMTP(Simple Mail Transfer Protocol)

RFC 0788에서 정의 되었는데 이후에도 많은 수정이 있다.

SMTP는 기본적으로 인터넷 메일을 서버로 송신하고 서버가 이 메일을 수신하는데 필요한 커멘트 및 표준 절차등을 정의하고 있다.

Java Mail API의 주요 구성 요소

이 글에서는 Java Mail API의 모든 클래스에 대해서 알아보지는 않을 것이며, 가장 중심적인 역할을 하는 클래스인 javax.mail.Session, javax.mail.Store, javax.mail.Transport, javax.mail.Folder, javax.mail.Message 클래스에 대해서 알아볼 것이다. 실제로 이 다섯개의 클래스만 알맞게 사용하면 매우 손쉽게 메일 시스템을 구축할 수 있다.

javax.mail.Session

javax.mail.Session은 Java Mail API를 사용하는 출발점이 되는 클래스로서 다양한 메일 프로토콜을 위한 서비스 프로바이더 구현(Service Provider Implementation; SPI)을 나타내는 클래스를 로딩하고 제어할 수 있는 메소드를 제공하고 있다. 예를 들어, javax.mail.Store 클래스의 인스턴스는 javax.mail.Session 클래스를 통해서 구할 수 있다. (여기서 서비스 프로바이더는 Java Mail API를 이용하여 구현 클래스 계층을 제공하는 개발자는 벤더를 의미한다. 현재 Java Mail API는 IMAP, SMTP, POP3 프로토콜에 대한 구현 계층을 제공하고 있다.)

javax.mail.Store

javax.mail.Store 클래스는 특정한 메일 프로토콜을 이용하여 메일의 읽기, 쓰기, 감시, 검색 등을 할 수 있도록 해 준다. Session 클래스를 사용하여 구할 수 있으며, 메일 저장소를 추상화한 javax.mail.Folder에 접근할 수 있도록 해 준다. 서비스 프로바이더는 Store 클래스를 알맞게 구현해야 한다.

javax.mail.Folder

javax.mail.Folder 클래스는 메일 메세지에 계층적 구조를 제공하며 메일 메세지에 접근할 수 있도록 해 준다. 메일 메세지는 javax.mail.Message 클래스의 객체로 표현된다. 서비스 프로바디어는 Folder 클래스를 알맞게 구현해야 한다.

javax.mail.Transport

javax.mail.Transport 클래스는 특정한 프로토콜을 사용하여 메세지를 전송할 때 사용된다. 서비스 프로바이더는 이 클래스를 알맞게 구현해야 한다.

javax.mail.Message

javax.mail.Message 클래스는 주제, 수신자의 이메일주소, 발송자의 이메일 주소, 보낸 날짜와 같은 실제 이메일 메세지의 세부 사항을 나타낸다. 서비스 프로바이더는 자신이 사용하는 프로토콜에 알맞게 Message를 구현해야 한다.

Java Mail API와 JAF

Java Mail API는 메시지에 다양한 포맷을 사용할 수 있도록 하기 위해 JAF를 사용한다. JAF는 별도의 확장 API로서 다양한 데이터 형식을 이용하여 작업하는 방법을 통합하기 위해 작성되었다. 실제로 JAF를 이용하면 간단한 텍스트 데이터에서부터 이미지, 비디오 등의 매우 복잡한 멀티 미디어 데이터로 구성된 문서까지 다양한 데이터를 제공할 수 있다.

+ Recent posts