Mailchimp Mandrill integration
Mailchimp Mandrill is a delivery service for transactional emails from websites and application.
Integrating Mailchimp Mandrill is a powerfull way of triggering scripts or flows by e-mail.
Webhooks in Windmill
Webhooks in Windmill are a versatile and efficient method for triggering scripts or flows based on external events. Every script or flow created within the platform is automatically assigned a set of autogenerated webhooks, which can be found on the "Detail" page of the script/flow.
Combined with a token created in Windmill, these webhooks can be interacted with using standard web technologies, making them compatible with a broad range of external systems and services, including Mailchimp Mandrill for email-triggered executions.
Each script or flow has webhook endpoints. Bearer token must be passed as either an Authorization: Bearer <TOKEN> header, or as a token query parameter: https://<instance>/<route>?token=<TOKEN>
Using Mailchimp to trigger Windmill webhooks from emails
All the details on the Mailchimp side are explained in this tutorial.
The flow we used for the example is available on Windmill Hub.
Here are the steps to follow:
-
Create a script or flow in Windmill. Make sure it has an input designed to receive the parsed results (for example a string called "mandrill_events").
-
Sign up to Mailchimp (we used the free trial at first).
-
Go to the inbound menu of Mailchimp Mandrill.
-
Add a domain or sub-domain. For example
webhooks.domain.com
. -
Add the MX records to your DNS provider and validate them from Mandrill.
-
From Mandrill, click the dropdown next to the
Test DNS Settings
button, selectRoutes
, and then select theAdd New Route button
. Configure a new route. That will be the accepted email(s) to trigger your script or flow. Please note that these e-mail adresses do not have to pre-exist to be treated by Mailchimp. -
From Windmill, go to the
Details
menu of your script or flow. If not any, create a token. Pick a webhook (UUID/Async
is commonly preferred). -
In Mandrill's "Post to URL" box, paste the webhook in the form
https://app.windmill.dev/.../rest_of_the_webhook/?token=TOKEN
. -
Click the
Test DNS Settings
button to check it's working.
Now you're all set!
Maybe you want to deal with the specific elements of the email. It is likely the payload has been sent as a string, so add a parsing to json step and use its results as inputs for further steps.
Parses payload to Json. Code below:
export async function main(x) {
return JSON.parse(x);
}
With "x" = our only input flow_input.mandrill_events
.
Extract information from directly routed e-mails
If your routing rules are set to capture emails that are directly addressed to certain recipients (for instance, any emails sent to name@company.com), extracting the relevant information from these emails is straightforward. It works as followed:
- Mailchimp already parses the e-mail's details.
- The parsed results are sent as an array, of which Windmill treats each element as a potential output & input.
In email systems, routing rules are not strictly tied to a single email address. Instead, they are flexible mechanisms that govern how an email server handles incoming messages based on various criteria.
A Mailbox Route allows at the server-level incoming emails to be automatically directed to specific destinations based on predefined rules. These rules match criteria like recipient address or subject line, and the system performs actions such as delivering the message to a mailbox, forwarding it, or applying filters
Thus, you can use the Mailchimp address effectively and have most emails be parsed directly without anyone knowing there is a Mailchimp domain. For instance: all emails sent to sales@domain.com and joe@domain.com will also be sent to windmill@windmill.domain.com to be analyzed and parsed by Windmill and if deemed relevant added to the CRM.
Then you just have to pick the details you want by "connecting inputs" of the JSON.parse step.
On the bottom right corner, relevant details from the email to be picked as inputs for further steps
Extract information from forwarded e-mails
If your routing rules are designed to process emails that are forwarded from certain recipients (for instance, any emails forwarded by name@company.com), you'll need an additional step to extract the relevant information from the original emails.
Indeed, Mailchimp already parses the e-mail's details but does it as a single e-mail. So for example the considered sender will be the one who forwarded the e-mail, not the sender of the original e-mail.
So we recommend you to add the following step an connecting "input_email" to results.c[0].msg.text
, c being the JSON parser step:
Example of a simple parser to get info from the forwarded email. Code below:
import re
def main(input_email):
from_pattern = re.compile(r'From: .+ <(.+)>')
subject_pattern = re.compile(r'Subject: (.+)')
date_pattern = re.compile(r'Date: (.+)')
to_pattern = re.compile(r'To: <(.+)>')
content_pattern = re.compile(r'\n\n(.*)\n', re.DOTALL)
from_field = re.search(from_pattern, input_email)
date_field = re.search(date_pattern, input_email)
subject_field = re.search(subject_pattern, input_email)
to_field = re.search(to_pattern, input_email)
content_field = re.search(content_pattern, input_email)
return {
'from': from_field.group(1) if from_field else None,
'date': date_field.group(1) if date_field else None,
'subject': subject_field.group(1) if subject_field else None,
'to': to_field.group(1) if to_field else None,
'content': content_field.group(1).strip() if content_field else None
}
On the bottom right corner, relevant details parsed from the forwarded email to be picked as inputs for further steps
Extract information from both directly routed and forwarded e-mails
At last, you may be in a situation where you want to extract the relevant details for both forwarded and directly routed e-mails. Meaning:
- if A directly sent e-mail, treat contact details of A ;
- if A forwarded e-mail from B, treat contact details of B.
Then you have two solutions:
- From Mailchimp, set-up two routes (and therefore, two workflows and two different emails configurations) to handle each cases. It has the advantage of being clear but it will be poor to handle human mistakes on the right address to send to.
- From Windmill, use branches to condition the behaviour of the workflow.
For example, have a script that reads the subject of the e-mail and returns a value if it contains "Fwd", value on which a conditional branch will depend.
Example of a script that returns true if the mail Topic contains given value. Code below:
export async function main(input: string, substring: string = 'Fwd'): Promise<Output> {
const containsSubstring = input.includes(substring);
return { containsSubstring };
}
interface Output {
containsSubstring: boolean;
}
Here is what it does when "input" = results.c[0].msg.headers.Subject
(c being the JSON.parse script) and string = "Fwd":
In this flow, when "Fwd" is not found, it considers it was not a forwarded e-mail and the default branch executes. Of course this can be customized to your needs.
How to go further?
The present example is a very simple use case: when an email is transfered to a given address, it triggers a flow that reports the main details of the mail to Slack.
However, you could go with much more complex workflows:
- Play with branches branches and have this flow report on different media depending of the content of the e-mail.
- The email could be dealt with to automatically update a CRM (e.g. Hubspot, Salesforce, Airtable).
- Use the parsed details to branch the execution of your flow on a condition.
- Have OpenAI summarize the content of the email.
- Invoicing and Accounting: If your business receives invoices or receipts via email, you can parse these emails to extract relevant information and automatically update your accounting software or database.
- Monitoring and Alerting: If you're receiving system or application alerts via email, you can parse these emails and trigger specific workflows based on the type of alert. For example, you could automatically create a task in a project management tool, send a message in a Slack channel, or even trigger a script to attempt to resolve the issue automatically.
On top of much more custom-made uses only you can think of.