High Quality JMS Messaging.

Outbound Bridges

An outbound bridge is bound to a queue or topic where it receives JMS messages. The format of the JMS messages is dependent on the transformer class of the outbound bridge. The JMS message will be transformed into a JavaMail message and will be sent to a configured mail server via SMTP.

Creating an Outbound Bridge

A queue or a topic serves as input source to the outbound bridge. Before you create the bridge, ensure that the queue or topic exists.

Use the SwiftMQ Explorer, connect, and open the JavaMail Bridge Extension Swiftlet node. Below is a node called "Outbound Bridges". Select it and do a right mouse click:

After clicking "Create a new Entity" you'll see a dialog window where you can specify your bridge configuration:

Field description:

Attribute Meaning
Name Some unique name of your choice.
Enabled If checked, the bridge will be activated. Since you have not finished your configuration yet, don't enable it now!
Error Policy Defines how to handle wrong input messages. See below. (Since 7.2.0)
Error Queue The error queue for this bridge.
Retry Interval The interval in ms in which the bridge tries to reconnect to the mail server in case the mail server is down.
SMTP Host The DNS name or the IP address of your mail server.
Source Name The name of the queue or the topic. The source has to be defined on the local router before you create the bridge.
Source Type Select either queue or topic here.
Transformer Class The name of the transformer class to use for this bridge (see below).

Error Policy (Since 7.2.0)

Each outbound bridge has an attribute "Error Policy" which defines how to proceed in case the transformation fails (transformer throws an exception). Possible values for the error policy are:

Policy Meaning
delete The input message will be deleted.
error_queue (default) The input message will be flagged as error and will be send to the defined error queue, see below.
retry It will be retried to transform the input message within the next interval. This is only useful if the transformer depends on some kind of external state, e.g. availablity of a database.

If the error policy is "error_queue", the attribute "error-queue" must contain a local queue name. This queue can be shared by all or unique per outbound bridge. It will be automatically created when the bridge starts. In case the tranformer throws an exception, the input JMS message will be flagged with the following JMS vendor properties and forwarded to the error queue:

Property Meaning
JMS_SWIFTMQ_JAVAMAIL_ERROR_TEXT Contains the exception message from the transformer.
JMS_SWIFTMQ_JAVAMAIL_BRIDGE_NAME Contains the name of the outbound bridge.

Creating Default Headers

Default headers are useful if you want that every mail should be archived, for example. In that case you'd create a default header for "bcc". Or if you have a default subject to be used if no subject is specified in the JMS message. echnically, all defined default headers are set in the outgoing mail message and may be overwritten by headers, translated from the JMS message. So in fact, you don't need to specify any headers in the JMS message but can define it statically for the bridge as default headers.

You can set any valid Mime header, e.g. "X-Mailer" to store the name of an eMail client. The following header names are keywords and have special meaning/handling:

To define default headers, select the "Default Headers" node of your newly created bridge and do a right mouse click:

Then specify a default header:

Repeat these steps to create additional default headers.

Defining Header Translations

A header translation defines a translation from a JMS message property into a mail header. Any valid Mime header can be specified. Mail headers with names "sender", "from", "to", "reply-to", "cc", "bcc", and "subject" are keywords and have a special meaning/handling (see above "Creating Default Headers"). For example, if a JMS client sends newsletters with addresses from a database or an order confirmation to a customer, it would specify JMS message properties in its message which are translated into "from", "to", and "subject". If it stores the order number in the JMS message, a translation into "X-ORDERNO" could be defined.

The header translation is done after the default headers are set in the mail message. Therefore, they overwrite default headers.

To define a header translation, select the "Header Translations" node of your newly created bridge and do a right mouse click:

Then specify a header translation:

Here is a translation into a custom mail header:

Repeat these steps to create additional header translations.

Activating the Bridge

All necessary configurations have been finished now and you can activate the bridge by checking the "Enabled" attribute. Then save the configuration. The bridge is now active and is listening on the input source.

Tracing

To trace the bridge activity, enable the "swiftlet" trace space. The output goes to the "swiftlet.trace" file in your router's trace directory. Output will also be generated from the JavaMail classes. This output goes to the router's console window (System.out).

Outbound Message Transformer

An outbound message transformer is responsible for transforming a JMS message body into a JavaMail message body. It hides the actual message content and structure from the rest of the bridge. Therefore, a JMS client sends JMS messages which correspond with the configured transformer. Since transformers are pluggable, a developer can create his own transformer class which he uses for his JMS clients. This custom transformer class can use custom classes in a ObjectMessage, for example.

For convenience, the JavaMail Bridge Extension Swiftlet includes two pre-built outbound transformers which fit most requirements: A TextMessageTransformer which uses TextMessages and a MultipartTransformer which uses ObjectMessages with a java.util.ArrayList including text and attachments.

com.swiftmq.extension.javamail.outbound.TextMessageTransformer

The TextMessageTransformer accepts a JMS TextMessage and converts it to a mail message body with MIME type "text/plain". It's a very basic transformer. Following the relevant parts of a JMS client which sends a TextMessage to an outbound bridge with a configured TextMessageTransformer.

Example:

      TextMessage msg = session.createTextMessage();
      msg.setStringProperty("MailSubject","TestMail, please ignore!");
      msg.setStringProperty("FromAddress","testsender@mycompany.com");
      msg.setStringProperty("ToAddress","testrecipient@mycompany.com");
      for (int i = 0; i < nMsgs; i++)
      {
        msg.setText("Hello,\n\n This is Msg No: " + (i + 1));
        sender.send(msg);
      }

For this example, the outbound bridge configuration has to have defined header translations for "MailSubject" into "subject", "FromAddress" into "from", and "ToAddress" into "to".

com.swiftmq.extension.javamail.outbound.MultipartTransformer

The MultipartTransformer accepts an ObjectMessage containing a java.util.ArrayList. We have taken this approach to avoid having vendor specific classes at the JMS client. The ArrayList has to have the following structure:

Element Content
0 A String object containing the actual message.
1-n Optional. A HashMap object containing a single attachment.

The HashMap objects on the ArrayList elements 1-n are optional. One can also only send an ArrayList with a single String element. Such a HashMap contains each a single attachment plus some properties describing the attachment:

Property Content
filename The filename of the attachment. This is optional. If not set, the mail server will choose one.
content-type The MIME type. This is optional. If not set, the mail server will choose one (mostly "application/octet-stream").
content Contains the actual attachment in form of a byte[] array. This is mandatory.

The MultipartTransformer takes the ArrayList out of the ObjectMessage, converts the String from element 0 into the mail message body with MIME type "text/plain", and, if set, converts all HashMaps on elements 1-n into mail message body parts.

The following example contains the relevant code snippets of a JMS client which sends mails with attachments. It takes filenames as parameters of the main method, loads the files and sends them as attachments. As you will see, it's very easy:

Example:

      private static byte[] loadFile(String fn) throws Exception
      {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fn));
        int c;
        while ((c=bis.read())!=-1)
          bos.write(c);
        return bos.toByteArray();
      }

      private static String getExtension(String fn) throws Exception
      {
        String s = new File(fn).getName();
        return s.substring(s.lastIndexOf('.')+1);
      }

      // excerpt from the main method

      ObjectMessage msg = session.createObjectMessage();
      msg.setStringProperty("MailSubject","Multipart TestMail, please ignore!");
      msg.setStringProperty("FromAddress","testsender@mycompany.com");
      msg.setStringProperty("ToAddress","testrecipient@mycompany.com");
      for (int i = 0; i < nMsgs; i++)
      {
        ArrayList al = new ArrayList();
        // add the actual message at element 0
        al.add("Message No "+(i+1));
        // add all attachment files at 1-n
        if (args.length > 4)
        {
          for (int j=4;j<args.length;j++)
          {
            HashMap hm = new HashMap();
            hm.put("filename",args[j]);
            hm.put("content-type","application/"+getExtension(args[j]));
            hm.put("content",loadFile(args[j]));
            al.add(hm);
          }
        }
        msg.setObject(al);
        sender.send(msg);
      }

Well, that's it. Now you are able to send purchase order PDF files, software evaluation zip files and whatever you want as multipart eMails to your customers with just plain JMS from every node of a SwiftMQ router network!

Creating your own Transformer

The TextMessageTransformer and the MultipartTransformer are sufficient for most use cases. However, consider the case where you have already a working infrastructure where you send events to topics. For example, if a customer registers on a web site and there will be a message published containing the new customer record in XML form. So you could easily write a custom transformer which extracts the relevant data including eMail address out of the XML and send him a "Welcome to our site! Bla Bla" eMail. You only have to create an outbound bridge with your custom transformer and let the bridge listen to the particular topic. That's it!

To create a custom transformer, you have to implement one of the following interfaces:

      com.swiftmq.extension.javamail.outbound.Transformer

or

      com.swiftmq.extension.javamail.outbound.Transformer2

Click to view the javadoc.

Then create a jar file including your transformer class and all further custom classes you use and put it into the JavaMail Bridge Extension Swiftlet deployment directory. The Extension Swiftlet will be automatically redeployed and you can define your bridge.

Exception 'no object DCH for MIME type ...' with Java 6 and above

JavaMail internally uses the Java Activation Framework (JAF). This is included in the deployment bundle of this Swiftlet. JAF is included in Java 6 and above. Due to classloader issues (we don't set the thread context classloader), JAF does not find classes included in mail.jar which is also part of the deployment bundle.

The problem can be fixed by adding mail.jar to the system classpath (the "-cp ..." in the smqrX scripts).