XQuery/Sending E-mail

Motivation.
You want to send an e-mail message from within an XQuery. This is frequently done when a report has finished running or when a key event such as a task update has been done.
Method.
eXist provides a simple interface to e-mail.
Creating a mail session.
 let $mail-handle := mail:get-mail-session
 &lt;properties&gt;
 &lt;property name="mail.smtp.host" value="smtp.your-domain.com"/&gt;
 &lt;property name="mail.smtp.port" value="25"/&gt;
 &lt;property name="mail.smtp.auth" value="false"/&gt;
 &lt;property name="mail.smtp.allow8bitmime" value="true"/&gt;
 &lt;/properties&gt;
Format of the send-email function.
 mail:send-email($email as element()+, $server as xs:string?, $charset as xs:string?) xs:boolean+ where $email 
The email message is in the following format:
&lt;mail&gt;
 &lt;from/&gt;
 &lt;reply-to/&gt;
 &lt;to/&gt;
 &lt;cc/&gt;
 &lt;bcc/&gt;
 &lt;subject/&gt;
 &lt;message&gt;
 &lt;text/&gt;
 &lt;xhtml/&gt;
 &lt;/message&gt;
 &lt;attachment filename="" mimetype=""&gt;xs:base64Binary&lt;/attachment&gt; 
&lt;/mail&gt;
 $server The SMTP server. If empty, then it tries to use the local sendmail program.
 $charset The charset value used in the "Content-Type" message header (Defaults to UTF-8)
Sample Code.
xquery version "1.0";
declare namespace mail="http://exist-db.org/xquery/mail";
declare variable $message {
 &lt;mail&gt;
 &lt;from&gt;John Doe &amp;lt;sender@domain.com&amp;gt;&lt;/from&gt;
 &lt;to&gt;recipient@otherdomain.com&lt;/to&gt;
 &lt;cc&gt;cc@otherdomain.com&lt;/cc&gt;
 &lt;bcc&gt;bcc@otherdomain.com&lt;/bcc&gt;
 &lt;subject&gt;A new task is waiting your approval&lt;/subject&gt;
 &lt;message&gt;
 &lt;text&gt;A plain ASCII text message can be placed inside the text elements.&lt;/text&gt;
 &lt;xhtml&gt;
 &lt;html&gt;
 &lt;head&gt;
 &lt;title&gt;HTML in an e-mail in the body of the document.&lt;/title&gt;
 &lt;/head&gt;
 &lt;body&gt;
 &lt;h1&gt;Testing&lt;/h1&gt;
 &lt;p&gt;Test Message 1, 2, 3&lt;/p&gt;
 &lt;/body&gt;
 &lt;/html&gt;
 &lt;/xhtml&gt;
 &lt;/message&gt;
 &lt;/mail&gt;
if ( mail:send-email($message, 'mail server', ()) ) then
 &lt;h1&gt;Sent Message OK :-)&lt;/h1&gt;
else
 &lt;h1&gt;Could not Send Message :-(&lt;/h1&gt;
Example of JSON API.
Many e-mail services also provide a JSON API. For example, Mandrill has an e-mail service that allows you to send your first 12,000 emails per month for free. After you register for an account they will provide you with an API key. This API key can be used with the following to send an e-mail message:
xquery version "3.0";
module namespace mandrill="http://haptixgames.com/nosql-asset/mandrill";
import module namespace xqjson="http://xqilla.sourceforge.net/lib/xqjson";
import module namespace functx = "http://www.functx.com";
declare namespace httpclient="http://exist-db.org/xquery/httpclient";
declare variable $mandrill:message-send := 'https://mandrillapp.com/api/1.0/messages/send.json';
declare function mandrill:send($api-key as xs:string, 
 $from-email as xs:string, 
 $from-name as xs:string, 
 $to-email as xs:string, 
 $subject as xs:string,
 $body-text as xs:string)
 let $email-xml := 
 &lt;json type="object"&gt;
 &lt;pair name="key" type="string"&gt;{$api-key}&lt;/pair&gt;
 &lt;pair name="message" type="object"&gt;
 &lt;pair name="text" type="string"&gt;{$body-text}&lt;/pair&gt;
 &lt;pair name="subject" type="string"&gt;{$subject}&lt;/pair&gt;
 &lt;pair name="from_email" type="string"&gt;{$from-email}&lt;/pair&gt;
 &lt;pair name="from_name" type="string"&gt;{$from-name}&lt;/pair&gt;
 &lt;pair name="to" type="array"&gt;
 &lt;item type="object"&gt;
 &lt;pair name="email" type="string"&gt;{$to-email}&lt;/pair&gt;
 &lt;/item&gt;
 &lt;/pair&gt;
 &lt;/pair&gt;
 &lt;/json&gt;
 let $response := httpclient:post(xs:anyURI($mandrill:message-send), xqjson:serialize-json($email-xml), false(), ())
 return
 if($response/@statusCode/string() eq "200")
 then 
 let $body := xqjson:parse-json(util:base64-decode($response/httpclient:body/text()))
 return
 if($body/item/pair[@name/string() eq 'status']/text() eq 'sent')
 then true()
 else false()
 else false()
Below is a refined version of the above Mandrill script, which does not use the XQJSON module to serialize the XML message to JSON.
xquery version "3.0";
module namespace mandrill2="http://haptixgames.com/shared/modules/mandrill2";
import module namespace functx = "http://www.functx.com";
declare namespace httpclient="http://exist-db.org/xquery/httpclient";
 : Creates an email message from inputs. 
declare %private function mandrill2:create-message(
 $api-key as xs:string, 
 $subject as xs:string,
 $body,
 $attachments as element(attachment)*,
 $from-email as xs:string,
 $from-name as xs:string,
 $to-addresses)
 as element(json)
 &lt;mandrill&gt;
 &lt;key&gt;{$api-key}&lt;/key&gt;
 &lt;async&gt;false&lt;/async&gt;
 &lt;message&gt;
 if($body instance of element()*)
 then &lt;html&gt;{serialize($body)}&lt;/html&gt;
 else &lt;text&gt;{$body}&lt;/text&gt;
 &lt;subject&gt;{$subject}&lt;/subject&gt;
 &lt;from_email&gt;{$from-email}&lt;/from_email&gt;
 &lt;from_name&gt;{$from-name}&lt;/from_name&gt;
 for $address in $to-addresses
 return
 if($address instance of element(address))
 then
 &lt;to&gt;
 &lt;email&gt;{$address/email/text()}&lt;/email&gt;
 &lt;name&gt;{$address/name/text()}&lt;/name&gt;
 &lt;type&gt;to&lt;/type&gt;
 &lt;/to&gt;
 else
 &lt;to&gt;
 &lt;email&gt;{$address}&lt;/email&gt;
 &lt;type&gt;to&lt;/type&gt;
 &lt;/to&gt;
 { (: fake out serializer to write array :)
 if(count($to-addresses) eq 1)
 then &lt;to/&gt;
 else()
 {
 if($attachments)
 then
 for $attachment in $attachments
 return
 &lt;attachments&gt;
 &lt;type&gt;{$attachment/mime-type/text()}&lt;/type&gt;
 &lt;name&gt;{$attachment/file-name/text()}&lt;/name&gt;
 &lt;content&gt;{$attachment/content/text()}&lt;/content&gt;
 &lt;/attachments&gt;
 else ()
 { (: fake out serializer to write array :)
 if(count($attachments) eq 1)
 then &lt;attachments/&gt;
 else()
 &lt;/message&gt;
 &lt;/mandrill&gt;
 : Executes Mandrill APi send.
 : @param $api-uri Mandrill API URI (default:https://mandrillapp.com/api/1.0/messages/send.json)
 : @param $api-key your Mandrill API key
 : @param $body xs:string or XML fragment
 : @param $attachments sequence in the form of &lt;attachment&gt;&lt;mime-type&gt;text/plain&lt;/mime-type&gt;&lt;file-name&gt;some-file.txt&lt;/file-name&gt;&lt;content&gt;file-binary-content&lt;/content&gt;&lt;/attachment&gt;...
 : @param $to-addresses sequence of xs:string email addresses or sequence of &lt;address&gt;&lt;email&gt;some@domain.com&lt;/email&gt;&lt;name&gt;some guy&lt;/name&gt;&lt;/address&gt;...
declare function mandrill2:send(
 $api-uri as xs:anyURI,
 $api-key as xs:string,
 $from-email-name as xs:string,
 $from-email-address as xs:string,
 $subject as xs:string,
 $body,
 $attachments as element(attachment)*,
 $to-addresses) 
 let $message-xml :=
 mandrill2:create-message
 $api-key, 
 $subject,
 $body,
 $attachments,
 $from-email-address,
 $from-email-name,
 $to-addresses
 
 let $message-json :=
 util:serialize($message-xml,'method=json')
 let $response := 
 httpclient:post
 $api-uri, 
 $message-json, 
 false(), 
 &lt;headers&gt;
 &lt;header name="Content-Type" value="application/json"/&gt;
 &lt;/headers&gt;
 )
 return
 if($response/@statusCode/string() eq "200")
 then true()
 else false()
This example was provided by Chris Misztur on Sept. 21, 2013.