From cd91418def49666cf8a728026485ec13c70cb0c4 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Tue, 23 Dec 2025 17:05:30 -0600 Subject: [PATCH 1/5] Retry-Logik --- worker.py | 53 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/worker.py b/worker.py index bd09549..44d4c22 100755 --- a/worker.py +++ b/worker.py @@ -59,30 +59,45 @@ def is_ses_bounce_notification(parsed): return 'mailer-daemon@us-east-2.amazonses.com' in from_h -def get_bounce_info_from_dynamodb(message_id): +def get_bounce_info_from_dynamodb(message_id, max_retries=3, retry_delay=1): """ Sucht Bounce-Info in DynamoDB anhand der Message-ID + Mit Retry-Logik für Timing-Issues Returns: dict mit bounce info oder None """ - try: - response = msg_table.get_item(Key={'MessageId': message_id}) - item = response.get('Item') - - if not item: - log(f"⚠ No bounce record found for Message-ID: {message_id}") - return None - - return { - 'original_source': item.get('original_source', ''), - 'bounceType': item.get('bounceType', 'Unknown'), - 'bounceSubType': item.get('bounceSubType', 'Unknown'), - 'bouncedRecipients': item.get('bouncedRecipients', []), - 'timestamp': item.get('timestamp', '') - } + import time - except Exception as e: - log(f"⚠ DynamoDB Error: {e}", 'ERROR') - return None + for attempt in range(max_retries): + try: + response = msg_table.get_item(Key={'MessageId': message_id}) + item = response.get('Item') + + if item: + # Gefunden! + return { + 'original_source': item.get('original_source', ''), + 'bounceType': item.get('bounceType', 'Unknown'), + 'bounceSubType': item.get('bounceSubType', 'Unknown'), + 'bouncedRecipients': item.get('bouncedRecipients', []), + 'timestamp': item.get('timestamp', '') + } + + # Nicht gefunden - Retry falls nicht letzter Versuch + if attempt < max_retries - 1: + log(f" Bounce record not found yet, retrying in {retry_delay}s (attempt {attempt + 1}/{max_retries})...") + time.sleep(retry_delay) + else: + log(f"⚠ No bounce record found after {max_retries} attempts for Message-ID: {message_id}") + return None + + except Exception as e: + log(f"⚠ DynamoDB Error (attempt {attempt + 1}/{max_retries}): {e}", 'ERROR') + if attempt < max_retries - 1: + time.sleep(retry_delay) + else: + return None + + return None def apply_bounce_logic(parsed, subject): From 6d9233922517d7e7eedd9af263003cec26bc1b12 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Tue, 23 Dec 2025 17:24:29 -0600 Subject: [PATCH 2/5] update all workers --- update-all-workers.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 update-all-workers.sh diff --git a/update-all-workers.sh b/update-all-workers.sh new file mode 100755 index 0000000..e69de29 From 929adcdbc9478b1a5f935d0c659fc40d1233a494 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Tue, 23 Dec 2025 17:25:47 -0600 Subject: [PATCH 3/5] content --- update-all-workers.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/update-all-workers.sh b/update-all-workers.sh index e69de29..88f3a47 100755 --- a/update-all-workers.sh +++ b/update-all-workers.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# update-all-workers.sh (smart version) + +DOMAINS=$(docker ps --filter "name=email-worker-" --format "{{.Names}}" | sed 's/email-worker-//') + +if [ -z "$DOMAINS" ]; then + echo "No workers found" + exit 1 +fi + +echo "Found workers: $DOMAINS" +echo "" + +for domain in $DOMAINS; do + echo "═══ $domain ═══" + ./manage-worker.sh "$domain" restart +done + +echo "✓ Done" \ No newline at end of file From 585bb285bf043b9fa266f1422e1224d6f6a84ccb Mon Sep 17 00:00:00 2001 From: knuthtimo-lab Date: Mon, 29 Dec 2025 10:17:24 +0100 Subject: [PATCH 4/5] ooo/forward plugin --- .../plugins/email_config/composer.json | 17 ++++ .../plugins/email_config/email_config.js | 20 ++++ .../plugins/email_config/email_config.php | 94 +++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 DMS/docker-data/roundcube/plugins/email_config/composer.json create mode 100644 DMS/docker-data/roundcube/plugins/email_config/email_config.js create mode 100644 DMS/docker-data/roundcube/plugins/email_config/email_config.php diff --git a/DMS/docker-data/roundcube/plugins/email_config/composer.json b/DMS/docker-data/roundcube/plugins/email_config/composer.json new file mode 100644 index 0000000..b5866cb --- /dev/null +++ b/DMS/docker-data/roundcube/plugins/email_config/composer.json @@ -0,0 +1,17 @@ +{ + "name": "local/email_config", + "type": "roundcube-plugin", + "description": "Email Configuration Plugin - Opens external email config interface", + "license": "MIT", + "version": "1.0.0", + "authors": [ + { + "name": "Custom Plugin", + "role": "Developer" + } + ], + "require": { + "php": ">=7.0.0", + "roundcube/plugin-installer": ">=0.1.3" + } +} diff --git a/DMS/docker-data/roundcube/plugins/email_config/email_config.js b/DMS/docker-data/roundcube/plugins/email_config/email_config.js new file mode 100644 index 0000000..fd75a8a --- /dev/null +++ b/DMS/docker-data/roundcube/plugins/email_config/email_config.js @@ -0,0 +1,20 @@ +/** + * Email Configuration Plugin - Client Side + */ +if (window.rcmail) { + rcmail.addEventListener('init', function(evt) { + rcmail.register_command('email_config_open', function() { + rcmail.http_post('plugin.email_config_generate_url', {}, + rcmail.set_busy(true, 'loading')); + }, true); + }); + + rcmail.addEventListener('responseafterplugin.email_config_generate_url', function(response) { + rcmail.set_busy(false); + if (response && response.url) { + window.open(response.url, '_blank'); + } else { + rcmail.display_message('Failed to generate configuration URL', 'error'); + } + }); +} diff --git a/DMS/docker-data/roundcube/plugins/email_config/email_config.php b/DMS/docker-data/roundcube/plugins/email_config/email_config.php new file mode 100644 index 0000000..c2eb7e5 --- /dev/null +++ b/DMS/docker-data/roundcube/plugins/email_config/email_config.php @@ -0,0 +1,94 @@ +register_action('plugin.email_config', array($this, 'email_config_init')); + $this->register_action('plugin.email_config_generate_url', array($this, 'generate_signed_url')); + + // Add button to toolbar in mail view + if ($this->rcmail->task == 'mail') { + $this->add_button(array( + 'command' => 'email_config_open', + 'label' => 'Email Config', + 'title' => 'Configure auto-reply and forwarding', + 'type' => 'link', + 'class' => 'button email-config', + ), 'toolbar'); + + $this->include_script('email_config.js'); + } + + // Add to settings menu + if ($this->rcmail->task == 'settings') { + $this->add_hook('settings_actions', array($this, 'settings_actions')); + } + } + + function settings_actions($args) + { + $args['actions'][] = array( + 'action' => 'plugin.email_config', + 'class' => 'email-config', + 'label' => 'Email Configuration', + 'title' => 'Configure email rules', + ); + return $args; + } + + function email_config_init() + { + $this->register_handler('plugin.body', array($this, 'email_config_form')); + $this->rcmail->output->set_pagetitle('Email Configuration'); + $this->rcmail->output->send('plugin'); + } + + function email_config_form() + { + $email = $this->rcmail->user->get_username(); + $url = $this->generate_url($email); + + $out = html::div(array('class' => 'box'), + html::p(null, 'Manage your email configuration including out-of-office auto-replies and forwarding rules.') . + html::p(null, + html::a(array( + 'href' => $url, + 'target' => '_blank', + 'class' => 'button mainaction', + ), 'Open Email Configuration') + ) + ); + + return $out; + } + + function generate_signed_url() + { + $email = $this->rcmail->user->get_username(); + $url = $this->generate_url($email); + + header('Content-Type: application/json'); + echo json_encode(array('success' => true, 'url' => $url)); + exit; + } + + private function generate_url($email) + { + $expires = time() + 3600; // 1 hour validity + $data = $email . '|' . $expires; + $signature = hash_hmac('sha256', $data, $this->secret_key); + + return $this->config_url . '/?email=' . urlencode($email) + . '&expires=' . $expires + . '&signature=' . $signature; + } +} From 1b33990d868d33e92fd520b729e94bd12130b66b Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Mon, 29 Dec 2025 13:34:13 -0600 Subject: [PATCH 5/5] update --- .../plugins/email_config/composer.json | 8 +- .../plugins/email_config/email_config.js | 20 ---- .../plugins/email_config/email_config.php | 109 ++++++++---------- .../plugins/email_config/localization/en.inc | 3 + .../email_config/localization/en_US.inc | 3 + 5 files changed, 52 insertions(+), 91 deletions(-) delete mode 100644 DMS/docker-data/roundcube/plugins/email_config/email_config.js create mode 100644 DMS/docker-data/roundcube/plugins/email_config/localization/en.inc create mode 100644 DMS/docker-data/roundcube/plugins/email_config/localization/en_US.inc diff --git a/DMS/docker-data/roundcube/plugins/email_config/composer.json b/DMS/docker-data/roundcube/plugins/email_config/composer.json index b5866cb..9d75386 100644 --- a/DMS/docker-data/roundcube/plugins/email_config/composer.json +++ b/DMS/docker-data/roundcube/plugins/email_config/composer.json @@ -1,15 +1,9 @@ { "name": "local/email_config", "type": "roundcube-plugin", - "description": "Email Configuration Plugin - Opens external email config interface", + "description": "Email Configuration - Manage OOO and Forwarding", "license": "MIT", "version": "1.0.0", - "authors": [ - { - "name": "Custom Plugin", - "role": "Developer" - } - ], "require": { "php": ">=7.0.0", "roundcube/plugin-installer": ">=0.1.3" diff --git a/DMS/docker-data/roundcube/plugins/email_config/email_config.js b/DMS/docker-data/roundcube/plugins/email_config/email_config.js deleted file mode 100644 index fd75a8a..0000000 --- a/DMS/docker-data/roundcube/plugins/email_config/email_config.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Email Configuration Plugin - Client Side - */ -if (window.rcmail) { - rcmail.addEventListener('init', function(evt) { - rcmail.register_command('email_config_open', function() { - rcmail.http_post('plugin.email_config_generate_url', {}, - rcmail.set_busy(true, 'loading')); - }, true); - }); - - rcmail.addEventListener('responseafterplugin.email_config_generate_url', function(response) { - rcmail.set_busy(false); - if (response && response.url) { - window.open(response.url, '_blank'); - } else { - rcmail.display_message('Failed to generate configuration URL', 'error'); - } - }); -} diff --git a/DMS/docker-data/roundcube/plugins/email_config/email_config.php b/DMS/docker-data/roundcube/plugins/email_config/email_config.php index c2eb7e5..7522257 100644 --- a/DMS/docker-data/roundcube/plugins/email_config/email_config.php +++ b/DMS/docker-data/roundcube/plugins/email_config/email_config.php @@ -1,37 +1,13 @@ add_texts('localization/', false); + $this->add_hook('settings_actions', array($this, 'settings_actions')); $this->register_action('plugin.email_config', array($this, 'email_config_init')); - $this->register_action('plugin.email_config_generate_url', array($this, 'generate_signed_url')); - - // Add button to toolbar in mail view - if ($this->rcmail->task == 'mail') { - $this->add_button(array( - 'command' => 'email_config_open', - 'label' => 'Email Config', - 'title' => 'Configure auto-reply and forwarding', - 'type' => 'link', - 'class' => 'button email-config', - ), 'toolbar'); - - $this->include_script('email_config.js'); - } - - // Add to settings menu - if ($this->rcmail->task == 'settings') { - $this->add_hook('settings_actions', array($this, 'settings_actions')); - } } function settings_actions($args) @@ -39,56 +15,61 @@ class email_config extends rcube_plugin $args['actions'][] = array( 'action' => 'plugin.email_config', 'class' => 'email-config', - 'label' => 'Email Configuration', - 'title' => 'Configure email rules', + 'label' => 'email_config', + 'domain' => 'email_config', ); return $args; } function email_config_init() { + $rcmail = rcube::get_instance(); $this->register_handler('plugin.body', array($this, 'email_config_form')); - $this->rcmail->output->set_pagetitle('Email Configuration'); - $this->rcmail->output->send('plugin'); + $rcmail->output->set_pagetitle('Email Configuration'); + $rcmail->output->send('plugin'); } function email_config_form() { - $email = $this->rcmail->user->get_username(); - $url = $this->generate_url($email); + $rcmail = rcube::get_instance(); + $email = $rcmail->user->get_username(); + $secret_key = 'SHARED_SECRET_KEY_987654321'; + $config_url = 'http://localhost:3008'; + $expires = time() + 3600; + $data = $email . '|' . $expires; + $signature = hash_hmac('sha256', $data, $secret_key); + $url = $config_url . '/?email=' . urlencode($email) . '&expires=' . $expires . '&signature=' . $signature; - $out = html::div(array('class' => 'box'), - html::p(null, 'Manage your email configuration including out-of-office auto-replies and forwarding rules.') . - html::p(null, - html::a(array( - 'href' => $url, - 'target' => '_blank', - 'class' => 'button mainaction', - ), 'Open Email Configuration') - ) - ); + $out = ' +
+
+ + + +

Email Rules Configuration

+
+ +
+

Signed in as:

+

' . htmlspecialchars($email) . '

+
+ +

+ Configure out-of-office auto-replies and email forwarding rules for your account. +

+ + +
'; return $out; } - - function generate_signed_url() - { - $email = $this->rcmail->user->get_username(); - $url = $this->generate_url($email); - - header('Content-Type: application/json'); - echo json_encode(array('success' => true, 'url' => $url)); - exit; - } - - private function generate_url($email) - { - $expires = time() + 3600; // 1 hour validity - $data = $email . '|' . $expires; - $signature = hash_hmac('sha256', $data, $this->secret_key); - - return $this->config_url . '/?email=' . urlencode($email) - . '&expires=' . $expires - . '&signature=' . $signature; - } } diff --git a/DMS/docker-data/roundcube/plugins/email_config/localization/en.inc b/DMS/docker-data/roundcube/plugins/email_config/localization/en.inc new file mode 100644 index 0000000..55c43eb --- /dev/null +++ b/DMS/docker-data/roundcube/plugins/email_config/localization/en.inc @@ -0,0 +1,3 @@ +