XQuery/Sending E-mail
Motivation
[edit | edit source]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
[edit | edit source]eXist provides a simple interface to e-mail.
Creating a mail session
[edit | edit source] let $mail-handle := mail:get-mail-session
(
<properties>
<property name="mail.smtp.host" value="smtp.your-domain.com"/>
<property name="mail.smtp.port" value="25"/>
<property name="mail.smtp.auth" value="false"/>
<property name="mail.smtp.allow8bitmime" value="true"/>
</properties>
)
Format of the send-email function
[edit | edit source]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:
<mail>
<from/>
<reply-to/>
<to/>
<cc/>
<bcc/>
<subject/>
<message>
<text/>
<xhtml/>
</message>
<attachment filename="" mimetype="">xs:base64Binary</attachment>
</mail>
$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
[edit | edit source]xquery version "1.0";
(: Demonstrates sending an email through Sendmail from eXist :)
declare namespace mail="http://exist-db.org/xquery/mail";
declare variable $message {
<mail>
<from>John Doe <sender@domain.com></from>
<to>recipient@otherdomain.com</to>
<cc>cc@otherdomain.com</cc>
<bcc>bcc@otherdomain.com</bcc>
<subject>A new task is waiting your approval</subject>
<message>
<text>A plain ASCII text message can be placed inside the text elements.</text>
<xhtml>
<html>
<head>
<title>HTML in an e-mail in the body of the document.</title>
</head>
<body>
<h1>Testing</h1>
<p>Test Message 1, 2, 3</p>
</body>
</html>
</xhtml>
</message>
</mail>
};
if ( mail:send-email($message, 'mail server', ()) ) then
<h1>Sent Message OK :-)</h1>
else
<h1>Could not Send Message :-(</h1>
Example of JSON API
[edit | edit source]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 :=
<json type="object">
<pair name="key" type="string">{$api-key}</pair>
<pair name="message" type="object">
<pair name="text" type="string">{$body-text}</pair>
<pair name="subject" type="string">{$subject}</pair>
<pair name="from_email" type="string">{$from-email}</pair>
<pair name="from_name" type="string">{$from-name}</pair>
<pair name="to" type="array">
<item type="object">
<pair name="email" type="string">{$to-email}</pair>
</item>
</pair>
</pair>
</json>
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";
(:~
: This module sends emails via Mandrill API.
:
: @author HaptixGames
: @version 1.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)
{
<mandrill>
<key>{$api-key}</key>
<async>false</async>
<message>
{
if($body instance of element()*)
then <html>{serialize($body)}</html>
else <text>{$body}</text>
}
<subject>{$subject}</subject>
<from_email>{$from-email}</from_email>
<from_name>{$from-name}</from_name>
{
for $address in $to-addresses
return
if($address instance of element(address))
then
<to>
<email>{$address/email/text()}</email>
<name>{$address/name/text()}</name>
<type>to</type>
</to>
else
<to>
<email>{$address}</email>
<type>to</type>
</to>
}
{ (: fake out serializer to write array :)
if(count($to-addresses) eq 1)
then <to/>
else()
}
{
if($attachments)
then
(
for $attachment in $attachments
return
<attachments>
<type>{$attachment/mime-type/text()}</type>
<name>{$attachment/file-name/text()}</name>
<content>{$attachment/content/text()}</content>
</attachments>
)
else ()
}
{ (: fake out serializer to write array :)
if(count($attachments) eq 1)
then <attachments/>
else()
}
</message>
</mandrill>
};
(:~
: 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 <attachment><mime-type>text/plain</mime-type><file-name>some-file.txt</file-name><content>file-binary-content</content></attachment>...
: @param $to-addresses sequence of xs:string email addresses or sequence of <address><email>some@domain.com</email><name>some guy</name></address>...
:)
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(),
(
<headers>
<header name="Content-Type" value="application/json"/>
</headers>
)
)
return
if($response/@statusCode/string() eq "200")
then true()
else false()
};
This example was provided by Chris Misztur on Sept. 21, 2013.