[mule-user] Dynamic "to" address on smtp:outbound-endpoint based on inbound object

134 views
Skip to first unread message

Alex Thieme

unread,
May 22, 2012, 2:06:24 PM5/22/12
to us...@mule.codehaus.org

I've tried all manner of examples to make the properties on the smtp outbound-endpoint dynamic based on the incoming object (e.g. email address). No luck.

In my case, there's a Message object that is put on "queue.passwordChangeEmail". Message/Password/email contains the address I want used in the "to" field.

I've included a minimal set of configuration that does send an email. All that's missing is accessing the Message object to use the email as the "to" field.

Some things I've tried and issues I've encountered:

If I don't include the object-to-string-transformer, then the email is never sent. Depending on where I reference the transformer, I get no email.

I've tried creating a custom transformer that calls muleMessage.setOutboundProperty("to", email), then returns a string as the body of the email. Despite where I've referenced the custom transformer, it never gets called.

I've tried xpath expressions like to="#[string:#[xpath:/Message/Password/email/text()]]" and to="[string:[xpath:/Message/Password/email/text()]]". Still no luck.

    <vm:endpoint name="queue.passwordChangeEmail" path="queue.passwordChangeEmail"/>
    <flow name="service.passwordChangeEmail">
        <description>
            Send the password change email
        </description>
        <vm:inbound-endpoint ref="queue.passwordChangeEmail"/>
        <object-to-string-transformer/>
        <smtp:outbound-endpoint
                host="localhost" port="25"
                subject="Password Change"
                to="us...@mule.codehaus.org" connector-ref="smtpConnector"/>
    </flow>

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           jaxb:version="2.0">

    <xs:element name="Message">
        <xs:complexType>
            <xs:choice>
                <xs:element name="Password" type="PasswordType"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="PasswordType">
        <xs:attribute name="email" type="xs:string" use="required"/>
    </xs:complexType>
</xs:schema>

public class PasswordChangeEmailTransformer extends AbstractMessageTransformer {

    public PasswordChangeEmailTransformer() {
        super();
        registerSourceType(DataTypeFactory.create(Message.class));
        setReturnDataType(DataTypeFactory.TEXT_STRING);
    }

    @Override
    public Object transformMessage(final MuleMessage muleMessage, final String encoding) throws TransformerException {
        System.out.println("muleMessage = " + muleMessage);
        final com.athieme.dartmouth.admin.Message message = (Message) muleMessage.getPayload();
        System.out.println("message = " + message);
        final PasswordType password = message.getPassword();
        System.out.println("password = " + password);
        final String email = password.getEmail();
        System.out.println("email = " + email);
        muleMessage.setOutboundProperty("to", email);
        return "Here's your password change email.";
    }
}




Alex Thieme

unread,
May 22, 2012, 2:32:19 PM5/22/12
to us...@mule.codehaus.org

I should also mentioned, populating the body of the email didn't seem to work. And, after one last try I believe I figured out the problem with assigning the "to" field. No transformer required, my path expression was wrong. I used to="#[xpath://Message/Password/@email]" with success.

Alex Thieme

unread,
Jun 2, 2012, 3:22:13 PM6/2/12
to us...@mule.codehaus.org
I still need a bit of help getting my flow working. I route an XML object (Message), transform this Message into a String using Freemarker, then wish to route this to an smtp outbound endpoint. The problem is, in transforming the Message into a String, I am no long able to access the original message using the XPath evaluator. Also, it seems I must access the payload using muleMessage.getPayload(Message.class) in order for the transformation to happen. I would prefer to use muleMessage.getPayload() to make this transformer more generally useful (I have many more messages and don't want a new transformer for every one). Using getPayload() results in "Template processing error: Expected <some attribute>. payload evaluated instead to freemarker.template.SimpleScalar".

Here's my flow definition and Freemarker transformer.

<vm:endpoint name="queue.password.email.admin" path="queue.password.email.admin"/>
    <flow name="service.password.admin.email">
        <vm:inbound-endpoint ref="queue.password.email.admin"/>
        <object-to-string-transformer/>
        <custom-transformer class="com.athieme.PayloadFreemarkerTransformer">
            <spring:property name="templateName" value="admin-password-change-request.ftl"/>
            <spring:property name="configuration" ref="freemarkerConfig"/>
        </custom-transformer>
        <smtp:outbound-endpoint
                host="localhost" port="25"
                subject="Password Change Request"
                to="#[xpath://Message/@email]" connector-ref="smtpConnector"/>
    </flow>

public Object transformMessage(final MuleMessage muleMessage, final String encoding) throws TransformerException {
        final Message payload = muleMessage.getPayload(Message.class);
        try {
            final StringWriter result = new StringWriter();
            final Map<String, Message> map = new HashMap<String, Message>();
            map.put("payload", payload);
            final Template template = configuration.getTemplate(templateName);
            template.process(map, result);
            final String str = result.toString();
            return str;
        } catch (final Exception e) {
            log.error(e, e);
        }
        return null;
    }

The resulting error is obvious once you understand what's wrong. The XPath evaluation is happening against the String not the Message. In my case, the String is an html page. At least, that's what I think is going on.

********************************************************************************
Message               : org.xml.sax.SAXParseException: The reference to entity "email" must end with the ';' delimiter. (javax.xml.transform.TransformerException)
Code                  : MULE_ERROR-64999
--------------------------------------------------------------------------------
Exception stack is:
1. The reference to entity "email" must end with the ';' delimiter. (org.xml.sax.SAXParseException)
  org.apache.xerces.parsers.AbstractSAXParser:-1 (null)
2. org.xml.sax.SAXParseException: The reference to entity "email" must end with the ';' delimiter. (javax.xml.transform.TransformerException)
  org.apache.xalan.transformer.TransformerIdentityImpl:502 (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/xml/transform/TransformerException.html)
3. org.xml.sax.SAXParseException: The reference to entity "email" must end with the ';' delimiter. (javax.xml.transform.TransformerException) (org.mule.api.transformer.TransformerException)
--------------------------------------------------------------------------------
Root Exception stack trace:
org.xml.sax.SAXParseException: The reference to entity "email" must end with the ';' delimiter.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:485)
at org.mule.module.xml.transformer.XmlToDomDocument.transformMessage(XmlToDomDocument.java:63)
    + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

David Dossot

unread,
Jun 8, 2012, 3:26:30 PM6/8/12
to us...@mule.codehaus.org
Could you place the message property transformer that sets the "to" outbound property before the Freemarker transformer? The Freemarker transformer shouldn't remove that property. --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email

Alex Thieme

unread,
Jun 12, 2012, 7:37:48 PM6/12/12
to us...@mule.codehaus.org

In fact, setting properties (in invocation scope) was exactly what I did to resolve this problem. Here's the working configuration for others. Thanks again.

<vm:endpoint name="queue.password.email.admin" path="queue.password.email.admin"/>
<flow name="service.password.admin.email">
<vm:inbound-endpoint ref="queue.password.email.admin"/>
<object-to-string-transformer/>
<message-properties-transformer scope="invocation">
<add-message-property key="to" value="#[xpath://Message/Password/@email]"/>
</message-properties-transformer>
<custom-transformer class="com.athieme.PayloadFreemarkerTransformer">
<spring:property name="templateName" value="password-change-request.ftl"/>
<spring:property name="configuration" ref="freemarkerConfig"/>
</custom-transformer>
<smtp:outbound-endpoint
host="localhost" port="25"
subject="Password Change Request"
to="#[header:INVOCATION:to]" connector-ref="smtpConnector"/>
</flow>
Reply all
Reply to author
Forward
0 new messages