From 1f2ead83db88e466cabb7e5a41fb1e5ca74d1b11 Mon Sep 17 00:00:00 2001 From: Alex Shostak Date: Mon, 13 Oct 2025 21:14:00 +0300 Subject: [PATCH 1/4] feat(mailgun): add support for EU region API endpoint - Added MAILGUN_REGION environment variable (US or EU) - Dynamically select API endpoint based on region - Fixes 401 errors for EU Mailgun accounts --- keep/providers/mailgun_provider/mailgun_provider.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/keep/providers/mailgun_provider/mailgun_provider.py b/keep/providers/mailgun_provider/mailgun_provider.py index 99f64601ed..9086dcae22 100644 --- a/keep/providers/mailgun_provider/mailgun_provider.py +++ b/keep/providers/mailgun_provider/mailgun_provider.py @@ -60,6 +60,7 @@ class MailgunProviderAuthConfig: class MailgunProvider(BaseProvider): MAILGUN_API_KEY = os.environ.get("MAILGUN_API_KEY") MAILGUN_DOMAIN = os.environ.get("MAILGUN_DOMAIN", "mails.keephq.dev") + MAILGUN_REGION = os.environ.get("MAILGUN_REGION", "US") # US or EU WEBHOOK_INSTALLATION_REQUIRED = True PROVIDER_CATEGORY = ["Collaboration"] @@ -207,7 +208,9 @@ def setup_webhook( sender = f"{sender}>" expression = f'({expression} and match_header("from", "{sender}"))' - url = "https://api.mailgun.net/v3/routes" + # Use correct API endpoint based on region + api_base = "https://api.mailgun.net" if MailgunProvider.MAILGUN_REGION.upper() == "US" else "https://api.eu.mailgun.net" + url = f"{api_base}/v3/routes" payload = { "priority": 0, "expression": expression, From fd4ed4afd028d9f134395c87c9221e529737ce1b Mon Sep 17 00:00:00 2001 From: Alex Shostak Date: Mon, 13 Oct 2025 21:31:04 +0300 Subject: [PATCH 2/4] fix(mailgun): correct API request format for route creation - Remove incorrect files parameter - Use only data parameter for form data - Fix duplicate payload passing - Resolves 400 bad request errors --- .../mailgun_provider/mailgun_provider.py | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/keep/providers/mailgun_provider/mailgun_provider.py b/keep/providers/mailgun_provider/mailgun_provider.py index 9086dcae22..fb54d92355 100644 --- a/keep/providers/mailgun_provider/mailgun_provider.py +++ b/keep/providers/mailgun_provider/mailgun_provider.py @@ -211,30 +211,40 @@ def setup_webhook( # Use correct API endpoint based on region api_base = "https://api.mailgun.net" if MailgunProvider.MAILGUN_REGION.upper() == "US" else "https://api.eu.mailgun.net" url = f"{api_base}/v3/routes" + + # Mailgun expects form data with multiple action fields payload = { "priority": 0, "expression": expression, "description": f"Keep {self.provider_id} alerting", - "action": [ - f"forward('{keep_api_url}&api_key={api_key}')", - "stop()", - ], } route_id = self.config.authentication.get("route_id") if route_id: + # Update existing route response = requests.put( - f"{url}/{self.config.authentication.get('route_id')}", - files=payload, + f"{url}/{route_id}", auth=("api", MailgunProvider.MAILGUN_API_KEY), - data=payload, + data={ + **payload, + "action": [ + f"forward('{keep_api_url}&api_key={api_key}')", + "stop()", + ], + }, ) else: + # Create new route response = requests.post( url, - files=payload, auth=("api", MailgunProvider.MAILGUN_API_KEY), - data=payload, + data={ + **payload, + "action": [ + f"forward('{keep_api_url}&api_key={api_key}')", + "stop()", + ], + }, ) response.raise_for_status() response_json = response.json() From 07083cd4f793117366edde2d181e6cb69afd33ee Mon Sep 17 00:00:00 2001 From: Alex Shostak Date: Tue, 14 Oct 2025 23:36:18 +0300 Subject: [PATCH 3/4] feat(mailgun): add UI dropdown for API region selection - Added api_region field to MailgunProviderAuthConfig with US/EU dropdown - Hybrid approach: UI field takes priority, falls back to MAILGUN_REGION env var - Maintains backward compatibility with environment variable configuration - Allows per-provider region configuration when needed --- .../mailgun_provider/mailgun_provider.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/keep/providers/mailgun_provider/mailgun_provider.py b/keep/providers/mailgun_provider/mailgun_provider.py index fb54d92355..38757c7ac4 100644 --- a/keep/providers/mailgun_provider/mailgun_provider.py +++ b/keep/providers/mailgun_provider/mailgun_provider.py @@ -46,6 +46,17 @@ class MailgunProviderAuthConfig: }, default="", ) + api_region: str = dataclasses.field( + metadata={ + "required": False, + "description": "Mailgun API region", + "hint": "Select 'US' for api.mailgun.net or 'EU' for api.eu.mailgun.net (uses env MAILGUN_REGION if not set)", + "sensitive": False, + "type": "select", + "options": ["US", "EU"], + }, + default="", + ) extraction: typing.Optional[list[dict[str, str]]] = dataclasses.field( default=None, metadata={ @@ -208,8 +219,13 @@ def setup_webhook( sender = f"{sender}>" expression = f'({expression} and match_header("from", "{sender}"))' - # Use correct API endpoint based on region - api_base = "https://api.mailgun.net" if MailgunProvider.MAILGUN_REGION.upper() == "US" else "https://api.eu.mailgun.net" + # Use correct API endpoint based on region (UI field takes priority, then env variable) + region = ( + self.authentication_config.api_region + or MailgunProvider.MAILGUN_REGION + or "US" + ).upper() + api_base = "https://api.mailgun.net" if region == "US" else "https://api.eu.mailgun.net" url = f"{api_base}/v3/routes" # Mailgun expects form data with multiple action fields From 6a0a324045b5207dd6d2d502d354634fed346b8c Mon Sep 17 00:00:00 2001 From: sanyo4ever Date: Wed, 15 Oct 2025 13:44:52 +0300 Subject: [PATCH 4/4] docs: Update mailgun and jira provider documentation snippets --- docs/snippets/providers/jira-snippet-autogenerated.mdx | 2 ++ docs/snippets/providers/mailgun-snippet-autogenerated.mdx | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/snippets/providers/jira-snippet-autogenerated.mdx b/docs/snippets/providers/jira-snippet-autogenerated.mdx index 3715144325..2375039b55 100644 --- a/docs/snippets/providers/jira-snippet-autogenerated.mdx +++ b/docs/snippets/providers/jira-snippet-autogenerated.mdx @@ -61,6 +61,8 @@ actions: Check the following workflow examples: - [create_jira_ticket_upon_alerts.yml](https://github.com/keephq/keep/blob/main/examples/workflows/create_jira_ticket_upon_alerts.yml) - [incident-enrich.yaml](https://github.com/keephq/keep/blob/main/examples/workflows/incident-enrich.yaml) +- [jira-create-ticket-on-alert.yml](https://github.com/keephq/keep/blob/main/examples/workflows/jira-create-ticket-on-alert.yml) +- [jira-transition-on-resolved.yml](https://github.com/keephq/keep/blob/main/examples/workflows/jira-transition-on-resolved.yml) - [jira_on_prem.yml](https://github.com/keephq/keep/blob/main/examples/workflows/jira_on_prem.yml) - [test_jira_create_with_custom_fields.yml](https://github.com/keephq/keep/blob/main/examples/workflows/test_jira_create_with_custom_fields.yml) - [test_jira_custom_fields_fix.yml](https://github.com/keephq/keep/blob/main/examples/workflows/test_jira_custom_fields_fix.yml) diff --git a/docs/snippets/providers/mailgun-snippet-autogenerated.mdx b/docs/snippets/providers/mailgun-snippet-autogenerated.mdx index 521dc778dd..e5239e4fe6 100644 --- a/docs/snippets/providers/mailgun-snippet-autogenerated.mdx +++ b/docs/snippets/providers/mailgun-snippet-autogenerated.mdx @@ -6,6 +6,7 @@ This provider requires authentication. - **email**: Email address to send alerts to (required: False, sensitive: False) - **sender**: Sender email address to validate (required: False, sensitive: False) - **email_domain**: Custom email domain for receiving alerts (required: False, sensitive: False) +- **api_region**: Mailgun API region (required: False, sensitive: False) - **extraction**: Extraction Rules (required: False, sensitive: False)