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.


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.

  12. The lack of support for 64-bit isn’t the only problem. This could probably be fixed. The real problem is that JMAPI uses the “Simple MAPI” interface in Windows. This is discouraged. From Microsoft docs:

    “The use of Simple MAPI functions is discouraged. They may be altered or unavailable in subsequent versions of Windows.”

    Link: https://msdn.microsoft.com/en-us/library/windows/desktop/dd296728%28v=vs.85%29.aspx

    It is not entirely clear to me what the alternative to “Simple MAPI” is, but it seems to be what is known as “Extended MAPI”.

  13. I had an issue about this and fixed it by adding an entry into the registry.
    Registry field is…
    Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Messaging Subsystem

    The value must be “MAPI” and the contents must be a STRING and have a value of “1” on a windows 10 x64 system.


Leave a reply to Aims Cancel reply

Categories