Sending a file attachement with Mule - mule

I have seen this answer but it does not show how you use the MEL to send the file in the value field. If you enter some value in there that is the content of the file. I assume you have to move the payload from the file endpoint connector to the attachment value property using MEL.
Also how can you set the content type dynamically
Mule SMTP - send email with attachment
Thanks
Jaco.

You can use the file-to-string-transformer to transform your file to string. You can also use Mule variables, properties, etc for defining the content type or other params. Example:
<file:inbound-endpoint path="/tmp/attachments" responseTimeout="10000"/>
<file:file-to-byte-array-transformer/>
<set-variable variableName="ct" value="test/plain" />
<set-attachment attachmentName="#[message.outboundProperties.filename]" value="#[payload]" contentType="#[flowVars['ct']]"/>
<set-payload value="this is my message"/>
<smtp:outbound-endpoint...

Related

Iterate over a directory and extract only file names without reading the payload

I am using the Mule 4.4 community edition on premise.
Thanks to help, I have been able to read a large file without consuming memory and processing it, which is all good (here).
Now building on this further - my use case is to read all .csv files from within a directory.
And then process them one by one:
\opt\out\
students.csv
teachers.csv
collesges.csv
....
So my plan was to list the files in the directory:
<sftp:list doc:name="List" config-ref="SFTP_Config" directoryPath="/opt/out">
<non-repeatable-iterable />
<sftp:matcher filenamePattern="#['*.csv' ]"
directories="EXCLUDE" symLinks="EXCLUDE" />
</sftp:list>
And then I wanted to only read file names from directory and not read payload.
As per this early access article we are advised to use <non-repeatable-iterable />. However, after the list file operation as per article when I try to extract attributes:
<set-payload doc:name="Set Payload" value="#[output application/json --- payload map $.attributes]"/>
No attributes are available... (my plan is to extract the file names and then run a for loop for each file name and then a choice condition to determine if file name has student, use student transformer, if teacher use teacher transformer, etc.)
However, as attributes are not available, I am not able to pass file names to the for loop (yet to be written).
So I changed from <non-repeatable-iterable /> to <repeatable-in-memory-iterable />
Code below:
<sftp:list doc:name="List" config-ref="SFTP_Config" directoryPath="/opt/out">
<repeatable-in-memory-iterable />
<sftp:matcher filenamePattern="#['*.csv' ]"
directories="EXCLUDE" symLinks="EXCLUDE" />
</sftp:list>
Using the above, I can extract the attributes of file names.
I am confused about the following:
The files to be processed in the above directory will be large (each file 700 MB), so while iterating the directory by using repeatable-in-memory-iterable, will it cause any memory issues? (I do not want to read file content, simply get file names at this stage)
Here is the complete payload till now (note - it does not contain any for loop to iterate over files, which I will plug in...)
<flow name="employee-process-flow">
<http:listener doc:name="Listener" config-ref="HTTP_Listener_config" path="/processFiles"/>
<set-variable value='#[now() as String { format: "ddMMuu" }]' doc:name="Set todays date as ddmmyy" doc:id="c6a91a41-65b1-46df-a720-9c13fe360b6b" variableName="today"/>
<sftp:list doc:name="List" config-ref="SFTP_Config" directoryPath="/opt/out">
<repeatable-in-memory-iterable />
<sftp:matcher filenamePattern="#['*.csv' ]"
directories="EXCLUDE" symLinks="EXCLUDE" />
</sftp:list>
<set-payload doc:name="Set Payload" value="#[output application/json --- payload map $.attributes]"/>
<foreach doc:name="For Each" >
<logger level="INFO" doc:name="Logger" message="we are here"/>
</foreach>
</flow>
The List operation returns a list of messages, and each has a payload and attributes. The content of the files is returned as the payload, in a lazy way, meaning that the file's content is read only if you try to access that element's payload.
It makes sense that if you a non-repeatable-iterator and don't access the payload of each item in the <foreach> then you should not have any memory issues, because the contents are not read.
By using in memory repeatable streaming it is possible that the entire payload is being read into memory. Try reading a file a few gigabytes in size and see what happens there.
I'm not sure what the problem is with the attributes. It should work the same in any streaming mode.
Note that if you plan on doing something with the attributes—other than printing them—then you should output to application/java instead of JSON, to avoid unneeded conversions to and from JSON. For example, in your flow the output is used as input for the <foreach>, so it would be better for it to be Java.
Example:
output application/java --- payload map $.attributes

Sending email attachment in Mule - Why am I getting payload attachment

I am sending an email with a csv attachment in Mule using the SMTP connector.
The email generated from Mule has two attachments on it.
The first is a file named Payload.
The second is the file I explicitly added myFile<date>.csv
How can I get rid of the Payload attachment? From my understanding what is in Payload file should be appearing as the content of the email. But that is not quite what is happening and instead it is appearing as an attachment.
Here is what my sub-flow that sends the email looks like. The payload coming in is a csv.
<sub-flow name="paymentReconSendMailSubFlow">
<set-attachment attachmentName="myFile-#[server.dateTime.format("yyyyMMddHHmmss") + '.csv']" value="#[payload]" contentType="application/csv" doc:name="Attachment"/>
<set-payload doc:name="Set Payload" value="#[null]"/>
<smtps:outbound-endpoint host="${smtp.host}" port="${smtp.port}" user="${smtp.username}" password="${smtp.password}" connector-ref="SMTP" to="${smtp.toAddress}" from="${smtp.fromAddress}" subject="BLAH" replyTo="${smtp.replyToAddress}" responseTimeout="10000" mimeType="text/html" doc:name="SMTP"/>
</sub-flow>
And here is what I get in my inbox.
It looks like Mule still has the content type of the message payload set to application/csv, so thinks your null payload is a CSV. Try adding mimeType="text/plain" to the set-payload element
Could you try to serialize the csv file to a byte array before attaching?
for example:
<file:inbound-endpoint path="${output.folder}" doc:name="File"/>
<file:file-to-byte-array-transformer doc:name="File to String"/>
<set-attachment value="#[message.payload]" contentType="application/csv"
attachmentName="#['myfile.csv']"
doc:name="Attachment" />
Let us know if is working and the issue is the serialisation of the file before sending

Mule ESB: File outputpattern doesn't translate the pattern

I'm using Mule ESB CE 3.4. I have a requirement where I'm reading the configuration information from database and using it as the file name for the file outbound endpoint. Here is an example code (the code may not work as I have only given an outline)
<file:connector name="File-Data" autoDelete="false" streaming="true" validateConnections="true" doc:name="File" />
.....
<!-- Gets the configuration from database using a transformer. The transformer populates the configuration entries in a POJO and puts that in a session. -->
<custom-transformer class="com.test.DbGetConfigsTransformer" doc:name="Get Integration Configs"/>
....<!-- some code to process data -->
<logger message="$$$: #[sessionVars['currentFeed'].getFilePattern()]" doc:name="Set JSON File Name" /> -->
<file:outbound-endpoint path="/temp" outputPattern="#[sessionVars['currentFeed'].getFilePattern()]" responseTimeout="10000" mimeType="text/plain" connector-ref="File-Data" doc:name="Save File"/>
The above code throws the following error:
1. The filename, directory name, or volume label syntax is incorrect (java.io.IOException)
java.io.WinNTFileSystem:-2 (null)
2. Unable to create a canonical file for /temp/Test_User_#[function:datestamp:YYYYMMddhhmmss.sss] (org.mule.api.MuleRuntimeException)
org.mule.util.FileUtils:354 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MuleRuntimeException.html)
3. Failed to route event via endpoint: DefaultOutboundEndpoint{endpointUri=file:///temp, connector=FileConnector
In the database table, the field name is called FilePattern and it has the value 'Test_User_#[function:datestamp:YYYYMMddhhmmss.sss]. If I hardcode the value or move this value to the mule configuration file
file.name=Test_User_#[function:datestamp:YYYYMMddhhmmss.sss]
and use the configuration property syntax (for e.g. ${file.name} in the 'outputpattern'), it works. But if I read the same from db and use it, it is not working and throwing the error. The logger displays as (which is read from the db)
$$$: Test_#[function:datestamp:YYYYMMddhhmmss.sss]
Any help is much appreciated.
If your datestamp format does not vary, you should just store the environment prefix in your db and use something like:
outputPattern="#[sessionVars['prefix']+server.dateTime.format('YYYYMMddhhmmss.sss')]"
If you need to use your current database values, you can use basic Java string methods to find the correct substrings. For example:
#[sessionVars['currentFeed'].getFilePattern().substring(0,sessionVars['currentFeed'].getFilePattern().indexOf('function')-2)+server.dateTime.format('YYYYMMddhhmmss.sss')]
If you use different datestamp formats, you can find that part as well using similar String methods. However, I still suggest you come up with an implementation that only stores the environment prefix in the db.

append specieal charecters in payload tag in Mule ESB

i want payload value like below in <http:outbound-endpoint>:
<set-variable variableName="url" value="#[json:url]" doc:name="Variable"></set-variable>
<set-variable variableName="payload" value="#[json:param]" doc:name="Variable"></set-variable>
<http:outbound-endpoint exchange-pattern="request-response" address="http://admin:admin##[url.substring(7)]" method="POST" doc:name="HTTP" password="admin" user="admin">
<set-payload value="action=start&params={input:#[payload]}&createTask=false&parts=all"/>
</http:outbound-endpoint>
but it is giving error.
thanks.
You can get rid of the error by replacing & with &
However, that is not your only problem.
payload is a reserved variable to hold the current payload. You can not use set-variable with variableName="payload", your setting will just be ignored when you call #[payload] later.
Your POST data would be something like action=start&params={input:yourdata}&createTask=false&parts=all. This is some kind of hybrid of JSON and HTTP GET syntax, and I doubt that this is what you are trying to achieve. If you want to send a POST request in key=val format, set a payload of type Map. If you want to send the request as JSON, set a payload with a JSON String, you have the object-to-json-transformer to help in Mule. If you want to have parameters in the URL, put them in the URL. But you can not mix these different syntaxes.

How to parse inbound e-mail when using Mule's IMAP transport?

I am just starting to learn mule so please forgive me if this is a very basic question.
I have successfully configured mule to monitor my mail box so whenever a mail comes in I write the mail to text file (just for testing).
Now I need to parse this mail and get the message / From / To from the mail.
<flow name="testFlow" doc:name="testFlow">
<imap:inbound-endpoint host="ip"
port="143" user="username" password="pwd" doc:name="IMAP"
responseTimeout="10000" transformer-refs="Message_Properties">
</imap:inbound-endpoint>
<file:outbound-endpoint path="C:\"
outputPattern="#[function:datestamp].dat" doc:name="File">
</file:outbound-endpoint>
</flow>
I thought I would be able to get the header information using the below expression (using expression transformer)
#[inboundProperties['email-header-name']]
but this doesn't seem to work. I also tried the below expressions but didn't work,
#[map-payload:HOST]
#[map-payload:MESSAGE]
#[map-payload:TIMESTAMP]
Can someone help? Also does anyone know if there is a document with the list of available expressions?
EDIT:
I included the logger to view the properties and it displayed all the properties but I couldnt find the body.. Also, I tried getting the fromAddress using
#[map-payload:fromAddress] and #[inboundProperties['fromAddress']]
but didn't work, can someone let me know where I am wrong?
The properties are something like below,
inbound.fromAddress=Service <service#xx.com>
inbound.subject=Test Final inbound.toAddresses=Service
Edit 2:
This is what I have tried but doesnt work :(
I am trying to retrieve the email subject and write to file or just show it using logger based on email subject but I am getting the below error.
ERROR 2013-02-07 19:22:45,275 [[test].connector.file.mule.default.dispatcher.01] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Could not find a transformer to transform "SimpleDataType{type=javax.mail.internet.MimeMessage, mimeType='*/*'}" to "SimpleDataType{type=java.io.InputStream, mimeType='*/*'}".
Code : MULE_ERROR-236
Can you let me know where I am making mistake?
<flow name="testFlow1" doc:name="testFlow1">
<imap:inbound-endpoint host="ip"
port="143" user="uname" password="pwd" doc:name="IMAP"
responseTimeout="10000" disableTransportTransformer="true">
</imap:inbound-endpoint>
<logger message="#[message.inboundProperties['inbound.fromAddress']]" level="INFO" doc:name="Logger"/>
<choice doc:name="Choice">
<when expression="message.inboundProperties['inbound.subject']=='plain test'">
<processor-chain>
<logger message="#[message.inboundProperties['inbound.fromAddress']]" level="INFO" doc:name="Logger"/>
</processor-chain>
</when>
<otherwise>
<processor-chain>
<file:outbound-endpoint path="C:\mule" outputPattern="#[function:datestamp].dat" responseTimeout="10000" disableTransportTransformer="true" doc:name="File">
</file:outbound-endpoint>
</processor-chain>
</otherwise>
</choice>
</flow>
Unfortunately the IMAP connector documentation doesn't list the message properties created when a new message is received. You can find all the created properties by adding:
<logger level="WARN" />
after the imap:inbound-endpoint. This will log all the message meta information, including properties, at WARN level.
You can also find the property names in the MailProperties JavaDoc. For example inbound.fromAddress is the inbound property that contains the sender's email address.
The message body is the text email content, unless it's a multi-part email. In that case, if the first part is text/plain, it will be set as the message payload, otherwise all parts will be available as inbound message attachments.