In this cookbook recipe, we're going to show how you can raise events to a pico using an external mail service, like mainIn. Transforming a mail message into an event isn't too difficult. The fun part is in parsing the body of the email to take further action. This recipe shows how to do that too.
Making a localhost engine available to the outside world
You'll need to have access to an email address that can be used. This implies also having access to a domain name. This can be challenging if you are running a node pico engine locally.
Making a localhost engine available to the outside world
Here at Pico Labs, we have a pico engine running on a Rapberry Raspberry Pi 3, and make it available to the outside world by using ngrok
which supplies "secure introspectable tunnels to localhost". This means that our engine can be accessed at https://assigned_id_1.ngrok.io
etc. where "assigned_id_1" is a pseudo-random identifier given to us by ngrok
. (The actual ID is redacted here, to avoid denial of service attacks, because ngrok
only allows us 20 uses per minute.) Another alternative is PageKite, but we'll use ngrok
in this cookbook.
Obtaining an email address that forwards to a webhook
Here we will show how to use CloudMailin which is a cloud service that assigns us an email address, which we can configure so that it does an HTTP POST to a webhook that we supply. We redact the actual address as "assigned_id_2" because CloudMailin only allows us 200 incoming email messages per month. The address we are using is assigned_id_2@cloudmailin.net
We have configured it to use https://assigned_id_1
.ngrok.io/sky/event/assigned_id_3<eci>/eid/mail/received
where "assigned_id_3<eci>" is an ECI (event channel identifier) which we created for the pico which we will be using to respond to mail:received
events. We'll call that assigned_id_3.
It should also be possible to install, configure, and run your own mailin server, but here we will use the CloudMailin service.
A ruleset that handles the mail:received
event
We created a pico, named Mail, and added a new channel with type
"secret" and name
"incoming mail", whose id
is known here as assigned_id_3<eci>, and added a ruleset containing this rule
...
This rule logs many things (and these log messages could be removed in a production application), extracts a few simple items from the incoming message and headers, and raises a new mail:parsed
event supplying those items as event attributes. You may wish to add rules in this or another ruleset for use within the Mail pico to respond to the mail:parsed
event. In our case, we wanted to pass the event on to another pico.
Forwarding to another pico
For this purpose, the same ruleset also contains a rule which is triggered by this mail:parsed
event, which parses out the ECI of the other pico from the "To" email address.
Code Block | ||
---|---|---|
| ||
rule mail_reactionrouter { select when mail parsed to re#assigned_id_2[+]([^@]*)@cloudmailin.net# setting(eci) event:send({"eci":eci, "domain":"test", "type":"test", "attrs":event:attrs()}) } |
...
The redacted "assigned_id_4" is an ECI of another pico to which the rule (in line 3) sends the test:test
event with parsed fields from the email message as attributes. We created a new channel for this purpose, with name
"email tests" and type
"secret" whose id
is known herein as "assigned_id_4". This is easily done in the "Channels" tab of the developer UI.
...
Code Block | ||
---|---|---|
| ||
global {
newline = (13.chr() + "?" + 10.chr()).as("RegExp")
}
rule test_test {
select when test test
foreach event:attr("text").split(newline) setting(request)
pre {
parts = request.klog("REQUESTED_EVENT").split(re#/#)
aurora = parts.length() == 2 && parts[0] == "aurora"
}
if aurora then noop()
fired {
raise aurora event parts[1]
}
} |
...
Each line is split into parts
using a forward slash as a separator. We ignore any lines which do not begin "aurora/" followed by just one slash-separated string of characters. They are ignored because the rule won't fire for such lines. For lines which match our expectation, in line 13 we raise an aurora event whose type is parts[1]
(the second slash-separated string of characters).
Sample email message
A sample email message might look like this:
...
The person composing the email message needs some knowledge of the events understood by the Aurora pico, but doesn't need to know where its pico is hosted, just the email address to which the message must be sent.
Caveats
In general, the most difficult part of turning an incoming email message into an event is parsing the message body to determine what further events need to be raised.
...
You will want to thoroughly test your rules before putting this cookbook into production.
Extended parsing
This modification to the rule in the Aurora pico which parses the incoming email message shows how we can extend the mini-language to include event attributes. Basically, lines in the message follow the syntax of standard event URL's starting with the domain portion, so that a line like
...