An inbound bridge is bound to a queue or topic where it sends JMS messages. It receives JavaMail messages from an account of a configured mail server either by POP3 or IMAP, respectively. The format of the JMS messages is dependent on the transformer class of the inbound bridge. The JavaMail message will be transformed into a JMS message and will be sent to the configured queue or topic.
A queue or a topic serves as output target to the inbound 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 "Inbound 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) |
| Mail Host | The DNS name or the IP address of your mail server. |
| Mail Host Account Folder | The name of the folder of the mail account. This is usually INBOX. |
| Mail Host Account Name | The name of the account at the mail server. |
| Mail Host Account Password | The account's password. |
| Mail Host Port | The port to use at the mail server. This is dependent on the protocol. For POP3 this is 110, for IMAP this is 143. |
| Protocol | Select either pop3 or imap here. |
| Max. Messages/Interval | Specifies how many messages should be retrieved from the mail server within one retrieve interval. This is to protect against denial-of-service attacks. |
| Retrieve Interval | Specifies the interval in ms in which the mail server is polled on new messages. |
| Target Message Delivery Mode | Specifies the JMS delivery mode to use. Select either persistent or non-persistent here. |
| Target Message Priority | Specifies the JMS priority to use. Select a value between 1 and 9 here. |
| Target Message Time To Live | Specifies the JMS expiration time for messages. 0 means no expiration. |
| Target Name | The name of the queue or the topic. The source has to be defined on the local router before you create the bridge. |
| Target Type | Select either queue or topic here. |
| Target Respect Flow Control | If checked, flow control delays returned from the target are respected and the bridge waits appropriately. |
| Transformer Class | The name of the transformer class to use for this bridge (see below). |
| Max. Message Size (KB) | Specifies the max. size of messages in KB received by this bridge. |
Each inbound 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 mail will be deleted. |
| flag | (default) The resulting JMS message will be flagged as error, see section about transformers. |
Keep in mind that you open SwiftMQ to the outside world once you create an inbound bridge. Someone could easily flood the mail account where you have defined an inbound bridge with a large number of huge messages which in turn will bring your JMS clients down. To protect against such denial-of-service attacks you can limit the maximum size of the messages itself and further limit the number of message to retrieve within one interval. For example, you can define a retrieve interval of 10 minutes (600000 ms), limit the max. number of messages to retrieve within one interval to 10, and finally set the maximum size of messages to 1 MB (1024 KB). Thus, everything is fine then.
The JMS message which will be generated from a JavaMail message can be enriched by JMS message properties. For example, you can create a default property which identifies the message to be created by this bridge and use it later in a message selector at your JMS client.
To define default properties, select the "Default Properties" node of your newly created bridge and do a right mouse click:
Then specify a default property:
Repeat these steps to create additional default properties.
A property translation defines a translation from any valid Mime mail header (e.g. "MessageID", "Received", "Content-Type", "X-Mailer") into a JMS message property. The following mail header names are keywords and have special meaning/handling:
The translation will be done after setting the default properties and before the actual message transformation will be done. Therefore, the translation overwrites default properties and may be overwritten from the transformer.
To define a property translation, select the "Property Translations" node of your newly created bridge and do a right mouse click:
Then specify a property translation:
Here is a translation of the mails "Message-ID" header into JMS property "MailMessageID":
Repeat these steps to create additional property translations.
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 to the input queue or topic, respectively.
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).
An inbound message transformer is responsible for transforming a JavaMail message body into a JMS message body. It hides the actual message content and structure from the rest of the bridge. Therefore, a JMS client receives JMS messages which corresponds 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 4 pre-built inbound transformers which fit most requirements: 2 TextMessageTransformers which use TextMessages and 2 MultipartTransformers which use ObjectMessages with a java.util.ArrayList including text and attachments.
Each inbound 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 mail will be deleted. |
| flag | (default) The resulting JMS message will be flagged as error, see below. |
There are 2 message properties used to flag the generated JMS messages whether the transformation process succeded or not:
| Property | Meaning |
|---|---|
| JMS_SWIFTMQ_JAVAMAIL_ERROR | A Boolean property which is true if the transformer failed. |
| JMS_SWIFTMQ_JAVAMAIL_ERROR_TEXT | In case of an error it contains the error message. |
If "JMS_SWIFTMQ_JAVAMAIL_ERROR" is true, the body of the JMS message is undefined and the "JMS_SWIFTMQ_JAVAMAIL_ERROR_TEXT" can be used to log the message or to send a notification to the mail sender in case a property translation has been defined on the "from" address.
The TextMessageTransformer accepts JavaMail messages with or without attachments. It uses the first body part with MIME type "text/plain" and transforms it into a JMS TextMessage. It's a very basic transformer. Following the relevant parts of a JMS client which receives a TextMessage from an inbound bridge with a configured TextMessageTransformer.
Example:
for (int i = 0; i < nMsgs; i++)
{
TextMessage msg = (TextMessage) receiver.receive();
boolean isError = msg.getBooleanProperty("JMS_SWIFTMQ_JAVAMAIL_ERROR");
if (isError)
{
System.out.println("Error: " + msg.getStringProperty("JMS_SWIFTMQ_JAVAMAIL_ERROR_TEXT"));
} else
{
System.out.println(">>> New Message from " + msg.getStringProperty("CustomerEMail"));
System.out.println(msg.getText());
System.out.println("<<< New Message");
}
}
For this example, the inbound bridge has to have a property translation from the "from" mail header into the "CustomerEMail" message property.
The GenericTextMessageTransformer works exactly as the TextMessageTransformer except it uses "text/*" to lookup the actual message to transform it into a JMS TextMessage. This transformer is useful for mails with a single part of MIME type "text/html" or "text/plain". For example, if a mail is received with a single part of MIME type "text/html" and the TextMessageTransformer is used, the mail is not transformed because TextMessageTransformer looks for a "text/plain" MIME type. Therefore, you have to use GenericTextMessageTransformer to get the mail transformed. The JMS TextMessage will contain the HTML formatted mail text.
The MultipartTransformer generates 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 the following structure:
| Element | Content |
|---|---|
| 0 | A String object containing the actual message. |
| 1-n | A HashMap object containing a single attachment. |
The bridge adds as many HashMaps to the ArrayList as attachments are contained in the JavaMail message. Each HashMap contains the following properties:
| Property | Content |
|---|---|
| filename | The filename of the attachment. |
| content-type | The MIME type. |
| content | Contains the actual attachment in form of a byte[] array. |
The following example contains the relevant code snippets of a JMS client which receives mails with attachments. It saves the attachments in the corresponding files. As you will see, it's very easy:
Example:
for (int i = 0; i < nMsgs; i++)
{
ObjectMessage msg = (ObjectMessage) receiver.receive();
boolean isError = msg.getBooleanProperty("JMS_SWIFTMQ_JAVAMAIL_ERROR");
if (isError)
{
System.out.println("Error: " + msg.getStringProperty("JMS_SWIFTMQ_JAVAMAIL_ERROR_TEXT"));
} else
{
ArrayList al = (ArrayList) msg.getObject();
System.out.println(">>> New Message from " + msg.getStringProperty("CustomerEMail"));
System.out.println(al.get(0));
System.out.println("<<< New Message");
for (int j = 1; j < al.size(); j++)
{
HashMap map = (HashMap) al.get(j);
System.out.println("Filename : " + map.get("filename"));
System.out.println("Content-Type: " + map.get("content-type"));
byte[] b = (byte[]) map.get("content");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream((String) map.get("filename")));
bos.write(b);
bos.flush();
bos.close();
}
}
}
Well, that's it. Now you are able to receive and process whatever you want as multipart eMails from your customers with just plain JMS on any node of a SwiftMQ router network!
The GenericMultipartTransformer works exactly as the MultipartTransformer except it uses "text/*" to lookup the actual message to transform it into a JMS ObjectMessage. This transformer is useful for mails with a single part of MIME type "text/html" or "text/plain". For example, if a mail is received with a single part of MIME type "text/html" and the MultipartTransformer is used, the mail is not transformed because MultipartTransformer looks for a "text/plain" MIME type. Therefore, you have to use GenericMultipartTransformer to get the mail transformed. The JMS ObjectMessage will contain the HTML formatted mail text at the element 0 of the ArrayList.
The TextMessageTransformer and the MultipartTransformer are sufficient for most use cases. However, there might be cases where you want to create your own content, e.g. an XML content in a TextMessage. To do this, you can create your own custom transformer.
To create a custom transformer, you have to implement the following interface:
com.swiftmq.extension.javamail.inbound.Transformer
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.