đ Executive Summary
TL;DR: This guide addresses the inefficiency of manually converting customer support emails into Trello cards. It provides a robust, automated solution using Mailgun for inbound email processing and a custom Python Flask application to automatically create Trello cards, streamlining support workflows and reducing manual overhead.
đŻ Key Takeaways
- Configure Mailgun Inbound Routes to receive emails and forward their parsed content as POST requests to a specified webhook URL.
- Develop a Python Flask application to act as a secure webhook listener, extracting essential email details (sender, subject, body-plain) from the Mailgun payload.
- Implement security best practices by verifying Mailgun webhook signatures using the private API key and loading all sensitive credentials (Trello API key/token, Mailgun API key) from environment variables.
Convert Customer Support Emails into Trello Cards automatically
Author: TechResolve Technical Writing Team
Introduction
In the fast-paced world of customer support and project management, efficiency is paramount. Manually sifting through support inboxes, copying details, and then creating corresponding tasks in a project management tool like Trello is not just tedious; itâs a productivity killer. This repetitive, error-prone process leads to delayed responses, missed requests, and a significant drain on your teamâs valuable time. Furthermore, relying on expensive, all-in-one SaaS solutions might not always align with your budget or specific workflow needs.
What if you could eliminate this manual overhead entirely? This tutorial will guide you through building a robust, automated system to convert incoming customer support emails directly into Trello cards. Weâll leverage a powerful combination of Mailgun for inbound email processing and a custom Python application, providing you with a cost-effective and highly customizable solution to streamline your support workflow. Get ready to transform your email inbox into an automated task creation engine, freeing your team to focus on what truly matters: resolving customer issues.
Prerequisites
Before we dive into the automation, ensure you have the following in place:
- Mailgun Account: An active Mailgun account with a configured domain capable of receiving inbound emails.
- Trello Account: An active Trello account where you have administrative access to the board and list where cards will be created.
- Trello API Key and Token: You will need to generate these credentials from your Trello account settings.
- Trello Board ID and List ID: Identify the specific Trello board and list where the new cards should appear. You can usually find these in the URL when viewing the board/list.
- Python 3.x: Installed on your development machine or server.
- pip: Pythonâs package installer, usually bundled with Python 3.x.
- A Server/VPS: A publicly accessible server or virtual private server to host your Python webhook listener. For local development and testing, ngrok can be used to expose your local machine to the internet.
Step-by-Step Guide
Step 1: Obtain Trello API Credentials and IDs
To interact with the Trello API, you need an API key and a token.
- Get Your Trello API Key: Visit https://trello.com/app-key. Your API key will be displayed prominently.
- Generate a Trello Token: On the same page, click âGenerate a new Tokenâ. Authorize the application, and copy the generated token. Keep both the key and token secure; they grant access to your Trello account.
-
Find Your Board ID: Navigate to your desired Trello board in your web browser. The URL will look something like
https://trello.com/b/BOARD_ID/board-name. Copy theBOARD_IDsegment. -
Find Your List ID: Open your Trello board. In the URL, add
.jsonto the end (e.g.,https://trello.com/b/BOARD_ID/board-name.json). This will show you the boardâs JSON data. Search for the name of your target list (e.g., âNew Support Ticketsâ) and find its correspondingidvalue.
Store these values safely; youâll use them in your Python script as environment variables or constants.
Step 2: Configure Mailgun Inbound Route
Mailgun will act as the intermediary, receiving emails and forwarding their parsed content to your Python application via a webhook.
- Add a Domain (if not already done): In your Mailgun control panel, navigate to âSendingâ > âDomainsâ and add your domain. Follow the DNS verification steps.
-
Create an Inbound Route: Go to âSendingâ > âRoutesâ. Click âCreate Routeâ.
-
Filter Expression: Choose âMatch Recipientâ. For example, if you want emails sent to
support@yourdomain.comto trigger the automation, entersupport@yourdomain.com. For broader matching, you can use*@yourdomain.com. -
Actions: Select âForwardâ and enter the URL of your webhook endpoint (e.g.,
https://yourserver.com/mailgun-webhook). This endpoint needs to be publicly accessible. - Description: Give it a descriptive name like âTrello Support Email Automationâ.
-
Filter Expression: Choose âMatch Recipientâ. For example, if you want emails sent to
When an email matches your route, Mailgun will parse its contents and send a POST request to your specified webhook URL, containing data like sender, subject, and body.
Step 3: Develop the Python Webhook Listener and Trello Card Creator
Now, letâs write the Python script that receives the Mailgun webhook, parses the email data, and creates a Trello card. Weâll use Flask for the web server and the requests library for API calls.
First, install the necessary libraries:
pip install Flask requests
Create a file named app.py and add the following code:
from flask import Flask, request, jsonify
import requests
import os
import hmac
import hashlib
app = Flask(__name__)
# --- Configuration (Load from Environment Variables for Security) ---
TRELLO_API_KEY = os.environ.get('TRELLO_API_KEY')
TRELLO_API_TOKEN = os.environ.get('TRELLO_API_TOKEN')
TRELLO_BOARD_ID = os.environ.get('TRELLO_BOARD_ID')
TRELLO_LIST_ID = os.environ.get('TRELLO_LIST_ID')
MAILGUN_API_KEY = os.environ.get('MAILGUN_API_KEY') # Used for webhook signature verification
if not all([TRELLO_API_KEY, TRELLO_API_TOKEN, TRELLO_BOARD_ID, TRELLO_LIST_ID, MAILGUN_API_KEY]):
print("ERROR: One or more environment variables are not set. Please set TRELLO_API_KEY, TRELLO_API_TOKEN, TRELLO_BOARD_ID, TRELLO_LIST_ID, and MAILGUN_API_KEY.")
exit(1)
# --- Trello API Constants ---
TRELLO_API_BASE = "https://api.trello.com/1"
def verify_mailgun_signature(token, timestamp, signature):
"""
Verifies the Mailgun webhook signature.
See: https://documentation.mailgun.com/en/latest/user_manual.html#securing-webhooks
"""
api_key_bytes = MAILGUN_API_KEY.encode('utf-8')
message = '{}{}'.format(timestamp, token).encode('utf-8')
digest = hmac.new(key=api_key_bytes, msg=message, digestmod=hashlib.sha256).hexdigest()
return digest == signature
@app.route('/mailgun-webhook', methods=['POST'])
def mailgun_webhook():
# 1. Verify Mailgun Signature (Crucial for Security)
signature = request.form.get('signature')
token = request.form.get('token')
timestamp = request.form.get('timestamp')
if not verify_mailgun_signature(token, timestamp, signature):
app.logger.warning("Mailgun signature verification failed for incoming webhook.")
return jsonify({"message": "Signature verification failed"}), 403
# 2. Extract Email Details from Mailgun Payload
sender = request.form.get('sender')
subject = request.form.get('subject')
body_plain = request.form.get('body-plain') # Use 'body-plain' for clean text
if not sender or not subject or not body_plain:
app.logger.error("Missing essential email data in Mailgun payload.")
return jsonify({"message": "Missing email data"}), 400
# 3. Prepare Trello Card Data
card_name = f"Support: {subject} (from {sender})"
card_description = f"Email from: {sender}\n\nSubject: {subject}\n\n---\n{body_plain}"
# 4. Create Trello Card
trello_url = f"{TRELLO_API_BASE}/cards"
params = {
'key': TRELLO_API_KEY,
'token': TRELLO_API_TOKEN,
'idList': TRELLO_LIST_ID,
'name': card_name,
'desc': card_description,
'idBoard': TRELLO_BOARD_ID # Optional, but good practice to include
}
try:
response = requests.post(trello_url, params=params)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
trello_card = response.json()
app.logger.info(f"Successfully created Trello card: {trello_card.get('url')}")
return jsonify({"message": "Trello card created successfully", "card_url": trello_card.get('url')}), 200
except requests.exceptions.RequestException as e:
app.logger.error(f"Error creating Trello card: {e}")
return jsonify({"message": f"Failed to create Trello card: {e}"}), 500
if __name__ == '__main__':
# For production, use a WSGI server like Gunicorn
# For development, you can run directly:
app.run(host='0.0.0.0', port=5000)
Code Logic Explained:
-
app = Flask(__name__): Initializes our Flask application. - Configuration: Sensitive API keys and IDs are loaded from environment variables for security, preventing hardcoding.
-
verify_mailgun_signature: This function verifies that webhook requests are genuinely from Mailgun using your Mailgun private API key, preventing unauthorized access. -
@app.route('/mailgun-webhook', methods=['POST']): Defines an endpoint/mailgun-webhookto listen for Mailgunâs POST requests. -
Payload Extraction:
request.form.get()extractssender,subject, andbody-plainfrom the Mailgun payload. -
Trello Card Preparation:
card_nameandcard_descriptionare formatted using the extracted email data. -
Trello API Call: A POST request is made to the Trello APIâs
/cardsendpoint with your credentials and the prepared card data. -
Error Handling: A
try...exceptblock catches and logs API call errors, returning appropriate HTTP status codes.
Step 4: Deploy and Secure Your Webhook Endpoint
For your Mailgun route to work, your Python application needs to be running on a publicly accessible server.
- Set Environment Variables: Before running your script, set the required environment variables on your server:
export TRELLO_API_KEY="YOUR_TRELLO_API_KEY"
export TRELLO_API_TOKEN="YOUR_TRELLO_API_TOKEN"
export TRELLO_BOARD_ID="YOUR_TRELLO_BOARD_ID"
export TRELLO_LIST_ID="YOUR_TRELLO_LIST_ID"
export MAILGUN_API_KEY="YOUR_MAILGUN_PRIVATE_API_KEY" # The one starting with 'key-'
Ensure MAILGUN_API_KEY is your private Mailgun API key (e.g., key-YOUR_SECRET_KEY), not the public one.
- Run the Application (Development/Testing):
For quick testing, you can run the Flask app directly:
python app.py
If youâre testing locally, use a tool like ngrok to expose your local http://localhost:5000/mailgun-webhook to a public URL that Mailgun can reach.
- Deploy for Production:
For a production environment, use a WSGI server like Gunicorn along with a reverse proxy like Nginx or Caddy. This ensures better performance, stability, and security.
Example Gunicorn command:
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 app:app
Then configure Nginx to proxy requests from your domain to Gunicorn (port 5000).
-
Update Mailgun Route: Ensure the âForwardâ action in your Mailgun route (from Step 2) points to the public URL of your deployed application (e.g.,
https://your-domain.com/mailgun-webhook). Donât forget HTTPS for production!
Once deployed, send a test email to the address configured in your Mailgun route. You should see a new Trello card appear in your designated list within seconds!
Common Pitfalls
- Mailgun Signature Verification Failure (403 Forbidden):
This is a common security measure. Double-check that the MAILGUN_API_KEY environment variable in your script is set to your Mailgun private API key (starts with key-) and not the public validation key. Also, ensure your serverâs time is synchronized, as a significant time skew can cause verification issues.
- Trello API Authentication/Authorization Errors (401, 403, 404):
Verify that your TRELLO_API_KEY and TRELLO_API_TOKEN are correct and have the necessary permissions (write access to the board/list). A 404 error could also indicate an incorrect TRELLO_BOARD_ID or TRELLO_LIST_ID.
- Network Connectivity Issues:
Ensure your serverâs firewall allows incoming connections on the port your Flask app is listening on (e.g., 5000). Also, confirm that your Mailgun webhook URL is correct and publicly accessible. If using HTTPS, ensure your server has a valid SSL certificate.
- Missing or Malformed Environment Variables:
The script explicitly checks for all required environment variables. If it exits with an error about missing variables, double-check your export commands or how you manage environment variables on your server.
Conclusion
Youâve successfully built an automated system that transforms raw customer support emails into actionable Trello cards, bypassing manual data entry and improving your teamâs responsiveness. This integration not only saves valuable time and reduces human error but also provides a centralized, trackable workflow for all support requests.
This solution is highly adaptable. Consider enhancing it further by:
- Advanced Parsing: Extracting specific information from email bodies (e.g., customer ID, priority level) using regular expressions or AI/NLP to populate custom fields or add labels in Trello.
- Attachment Handling: Downloading email attachments and uploading them to the Trello card.
- Notifications: Integrating with Slack or another communication tool to notify your team when a new card is created.
- Error Logging & Alerting: Implementing more robust logging and setting up alerts (e.g., via PagerDuty, Opsgenie) for failed Trello card creations.
By leveraging the power of APIs and a bit of custom code, youâve taken a significant step towards a more efficient and automated support operation. Happy automating!
đ Read the original article on TechResolve.blog
â Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)