Posted by: Brian de Alwis | March 28, 2011

JMAPI: Compose email messages with attachments from Java

I recently created a small bundle, JMAPI, to provide support for programmatically opening an email message on Windows platforms using MAPI. Although the bundle’s functionality is restricted to Windows, the bundle is cross-platform. The API is through a single class, jmapi.JMAPI, which supports three methods, one of which queries whether MAPI support is available.

JMAPI was carved from the ruins of the old Java Desktop Interface Components (JDIC) project. With most of JDIC's functionality has was absorbed into Java 6's java.awt.Desktop class, JDIC seems to have died. Not to mention that its binary distributions were wiped out with Oracle's transfer of java.net to Kenai.

The one useful component from JDIC that wasn't absorbed was its attempt to provide cross-platform support for opening mail messages in the user's mail client. Java 6 only supports the mailto: URL scheme. Although mailto: is useful, it is length-limited and, more importantly, doesn't provide for specifying message attachments; some clients provide for an "attachment" field, but its support is uneven.

Unfortunately JDIC's binary distribution is not OSGi-friendly. As my immediate needs were for a way to programmatically open a message using MAPI, I simply ripped out the support from JDIC, and did the minimum to make it work as an OSGi bundle. I didn't have the time to figure out how to rebuild the JNI support libraries (it has references to MFC and ATL), so I simply copied in the Windows DLL from JDIC 0.9.5; unfortunately this is 32-bit only. It may be possible to build using VisualStudio Express 2010 by someone with more Microsoft mojo than me.

Be aware that non-Outlook clients, such as Thunderbird, may need to perform a few extra steps to ensure that they are properly registered as the default email client.

Source is available up on github and is licensed under the same terms as JDIC with the LGPL.

About these ads

Responses

  1. [...] doing some development on a large RCP application. One recent task required using a Windows DLL to open an email message through MAPI. I encountered a few issues that I’m sure will bite other [...]

  2. Hi Brian,
    I have the exact similar requirement in which i have to attach the files in the default mail client. I downloded your code files from the link http://github.com/briandealwis/jmapi
    And imported the project in eclipse(RSA). I created a test file with the code

                if (JMAPI.isMapiSupported()) {
                    Message msg = new Message();
                    msg.setSubject("test!");
                    msg.setBody("Hello world");
    
                    List toAddresses = new LinkedList();
                    toAddresses.add("example@example.com");
                    msg.setToAddrs(toAddresses);
    
                    List attachPaths = new LinkedList();
                    //Must be absolute paths to file
                    attachPaths.add("C:\\Test.txt");
                    msg.setAttachments(attachPaths);
    
                    JMAPI.open(msg);
                }
    

    But when i try to run the file, i get the following error

    java.lang.UnsatisfiedLinkError: org/jdesktop/jdic/desktop/internal/impl/WinAPIWrapper.RegOpenKey(I[BI)[I
    	at org.jdesktop.jdic.desktop.internal.impl.WinAPIWrapper.WinRegQueryValueEx(WinAPIWrapper.java:170)
    	at jmapi.JMAPI.isMapiSupported(JMAPI.java:40)
    	at TestJMAPI.main(TestJMAPI.java:11)
    

    Requesting your help in resolving this.

    Thanks
    Aims

    • My guess: you’re using a 64-bit JVM? The JMAPI library is 32-bit only, unfortunately.

  3. Sorry but can you help me understand where can i check if its 32bit or 64 bit? I am running on Windows XP 2002 SP3.

    Thanks
    Aims

  4. When i run the java -version i got the following output
    java version “1.6.0_29″
    Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
    Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)

  5. I checked and it is 32 bit only. Can u suggest anything to fix this?
    Also can you explain if this will work with 32bit JVM installed on 64bit OS?

    Thanks
    Aims

    • If your 32-bit JVM works on your 64-bit OS, then this should work too. The only thing that comes to mind is that the DLL is not being resolved: ensure that it is on your PATH or java.lib.path (that is, providing you’re not using the bundle via OSGi), and verify that all the dependencies are being found with something like DependencyWalker.

  6. Yes it is working now. Thanks for all the help.
    Is there a version available for the 64bit as well now?

    Thanks
    Aims

    • When I was using this stuff, MAPI was 32-bit only. It seems there’s now 64-bit support too. I don’t have cycles to look into this further, but feel free to investigate and report back.

    • when i will run my code on server it will show following exception:::>
      org.jdesktop.jdic.desktop.internal.LaunchFailedException: Logon failed: Unexpected exception
      24 Nov 2012 20:41:22,904 http-8080-3 DEBUG annotation.ResponseStatusExceptionResolver – Resolving exception from handler [com.axa.ebi.controller.TopazController@1b00766]: org.jdesktop.jdic.desktop.internal.LaunchFailedException: Logon failed: Unexpected exception
      24 Nov 2012 20:41:22,904 http-8080-3 DEBUG support.DefaultHandlerExceptionResolver – Resolving exception from handler [com.axa.ebi.controller.TopazController@1b00766]: org.jdesktop.jdic.desktop.internal.LaunchFailedException: Logon failed: Unexpected exception
      24 Nov 2012 20:41:22,904 http-8080-3 DEBUG

      servlet.DispatcherServlet – Could not complete request

      • Why are you using MAPI on a server? Couldn’t you use java-mail instead?

  7. my requirement is to attached selected document document on email client. when i will run my code on spring source tool server than it will working file. but when i will deploy war file on tomcat server and run at that time it will give me exception:
    “org.jdesktop.jdic.desktop.internal.LaunchFailedException: Logon failed: Unexpected exception”.

    my code given below.

    System.loadLibrary(“jdic”);
    if (JMAPI.isMapiSupported()) {

    Message msg = new Message();
    //msg.setSubject(“test!”);
    // msg.setBody(“Hello world”);

    /*List toAddresses = new LinkedList();
    toAddresses.add(“example@example.com”);
    msg.setToAddrs(toAddresses);
    */
    List attachPaths = new LinkedList();
    //Must be absolute paths to file

    for(int i=0;i<dbpdfFileName.size();i++)
    {
    String pdfFilePath =(String) dbpdfFileName.get(i);
    //System.out.println("printpdf_pdfFilePath:::"+pdfFilePath);
    if (logger.isDebugEnabled())
    {
    logger.debug(moduleName + className + "viewstaicpdf" + "pdfFilePath::" + pdfFilePath);
    }
    File file = new File(pdfFilePath);

    boolean exists = file.isFile();
    if (logger.isDebugEnabled())
    {
    logger.debug(moduleName + className + "viewstaicpdf" + "File is exist ?::" + exists);
    }
    if (exists)
    {
    attachPaths.add(pdfFilePath);
    }
    }
    msg.setAttachments(attachPaths);
    JMAPI.open(msg);
    }

  8. Hi all, Actually I tried using above code to open email
    client with automatically attached document. But for me it is
    showing nothing and when i am getting that JMAPI.isSupported value
    as false for entering into loop. Because I tried to print the
    boolean value of that and it shown false. Can any one help me on
    this to how can I use this code in a correct way to open a email
    client with an attached pdf or any file. Pls do needful..

  9. Hi Brian, I am running 32 bit Window Xp machine. I am able
    to laod the dll. But Still I am getting false for
    JMAPI.isMapiSupported(). Is this possible if yes, How can i make it
    to return true ? Thanks in Advance! -Manish

    • Sounds like you’re either running on a 64-bit JVM or the DLL can’t be loaded. If you’re executing ominous a non-OSGi environment, you’ll need to ensure the included DLL is on your PATH.

  10. I am trying to use JMAPI in my application. I am getting
    the following error: java.lang.UnsatisfiedLinkError:
    org.jdesktop.jdic.desktop.internal.impl.WinAPIWrapper.RegOpenKey(I[BI)[I
    at
    org.jdesktop.jdic.desktop.internal.impl.WinAPIWrapper.RegOpenKey(Native
    Method) at
    org.jdesktop.jdic.desktop.internal.impl.WinAPIWrapper.WinRegQueryValueEx(WinAPIWrapper.java:170)
    at jmapi.JMAPI.isMapiSupported(JMAPI.java:40) at
    com.turborep.turbotracker.mail.SendQuoteMail.send(SendQuoteMail.java:120)
    at com.turborep.turbotracker.mail.SendEmail.main(SendEmail.java:77)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597) at
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212)
    at
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
    at
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
    at
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
    at
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
    at
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
    at
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
    at
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
    at
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662) My machine details: OS:
    Ubuntu 12.04 my code: if (JMAPI.isMapiSupported()) { Message msg =
    new Message(); msg.setSubject(“test!”); msg.setBody(“Hello world”);
    List toAddresses = new LinkedList();
    toAddresses.add(“gopi.nath@sysvine.com”);
    msg.setToAddrs(toAddresses); List attachPaths = new LinkedList();
    //Must be absolute paths to file
    attachPaths.add(attachFile.getPath());
    msg.setAttachments(attachPaths); JMAPI.open(msg); } Can you please
    help me on this.

  11. How can I send the email directly without opening the defualt mail client beforehand? is this not possible with MAPI32 ?

    • I don’t believe MAPI allows that to prevent trojans and worms from (easily) sending messages without the user’s approval. Use the java-mail APIs instead.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

Follow

Get every new post delivered to your Inbox.

Join 149 other followers