public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
[Quarantine] Allow to redirect all quarantine messages to a specific address [Web] Minor changes to quarantine UI
6c92688f
data/Dockerfiles/dovecot/quarantine_notify.py | 11 ++-
data/web/admin.php | 127 +++++++++++++-------------
data/web/css/site/admin.css | 3 +
data/web/inc/functions.quarantine.inc.php | 8 ++
data/web/lang/lang.de.json | 3 +-
data/web/lang/lang.en.json | 3 +-
docker-compose.yml | 2 +-
7 files changed, 87 insertions(+), 70 deletions(-)
Diff
diff --git a/data/Dockerfiles/dovecot/quarantine_notify.py b/data/Dockerfiles/dovecot/quarantine_notify.py
index 1c250bd3..6aefcab0 100755
--- a/data/Dockerfiles/dovecot/quarantine_notify.py
+++ b/data/Dockerfiles/dovecot/quarantine_notify.py
@@ -86,11 +86,18 @@ def notify_rcpt(rcpt, msg_count, quarantine_acl):
msg.attach(html_part)
msg['To'] = str(rcpt)
bcc = r.get('Q_BCC') or ""
+ redirect = r.get('Q_REDIRECT') or ""
text = msg.as_string()
if bcc == '':
- server.sendmail(msg['From'], str(rcpt), text)
+ if redirect == '':
+ server.sendmail(msg['From'], str(rcpt), text)
+ else:
+ server.sendmail(msg['From'], str(redirect), text)
else:
- server.sendmail(msg['From'], [str(rcpt)] + [str(bcc)], text)
+ if redirect == '':
+ server.sendmail(msg['From'], [str(rcpt)] + [str(bcc)], text)
+ else:
+ server.sendmail(msg['From'], [str(redirect)] + [str(bcc)], text)
server.quit()
for res in meta_query:
query_mysql('UPDATE quarantine SET notified = 1 WHERE id = "%d"' % (res['id']), update = True)
diff --git a/data/web/admin.php b/data/web/admin.php
index 811b0387..7e32a204 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -767,85 +767,82 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<?php
endif;
?>
- <form class="form" data-id="quarantine" role="form" method="post">
- <div class="row">
- <div class="col-sm-6">
- <div class="form-group">
- <label for="retention_size"><?=$lang['admin']['quarantine_retention_size'];?></label>
- <input type="number" class="form-control" name="retention_size" value="<?=$q_data['retention_size'];?>" placeholder="0" required>
- </div>
- </div>
- <div class="col-sm-6">
- <div class="form-group">
- <label for="max_size"><?=$lang['admin']['quarantine_max_size'];?></label>
- <input type="number" class="form-control" name="max_size" value="<?=$q_data['max_size'];?>" placeholder="0" required>
- </div>
+ <form class="form-horizontal" data-id="quarantine" role="form" method="post">
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="retention_size"><?=$lang['admin']['quarantine_retention_size'];?></label>
+ <div class="col-sm-8">
+ <input type="number" class="form-control" name="retention_size" value="<?=$q_data['retention_size'];?>" placeholder="0" required>
</div>
</div>
- <div class="row">
- <div class="col-sm-6">
- <div class="form-group">
- <label for="max_age"><?=$lang['admin']['quarantine_max_age'];?></label>
- <input type="number" class="form-control" name="max_age" value="<?=$q_data['max_age'];?>" min="1" required>
- </div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="max_size"><?=$lang['admin']['quarantine_max_size'];?></label>
+ <div class="col-sm-8">
+ <input type="number" class="form-control" name="max_size" value="<?=$q_data['max_size'];?>" placeholder="0" required>
</div>
- <div class="col-sm-6">
- <div class="form-group">
- <label for="sender"><span class="glyphicon glyphicon-copy"></span> <?=$lang['admin']['quarantine_bcc'];?></label>
- <input type="email" class="form-control" name="bcc" value="<?=htmlspecialchars($q_data['bcc']);?>" placeholder="">
- </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="max_age"><?=$lang['admin']['quarantine_max_age'];?></label>
+ <div class="col-sm-8">
+ <input type="number" class="form-control" name="max_age" value="<?=$q_data['max_age'];?>" min="1" required>
</div>
</div>
- <div class="row">
- <div class="col-sm-6">
- <div class="form-group">
- <label for="sender"><?=$lang['admin']['quarantine_notification_sender'];?>:</label>
- <input type="email" class="form-control" name="sender" value="<?=htmlspecialchars($q_data['sender']);?>" placeholder="quarantine@localhost">
- </div>
+ <hr>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="sender"><span class="glyphicon glyphicon-share-alt"></span> <?=$lang['admin']['quarantine_redirect'];?></label>
+ <div class="col-sm-8">
+ <input type="email" class="form-control" name="redirect" value="<?=htmlspecialchars($q_data['redirect']);?>" placeholder="">
</div>
- <div class="col-sm-6">
- <div class="form-group">
- <label for="subject"><?=$lang['admin']['quarantine_notification_subject'];?>:</label>
- <input type="text" class="form-control" name="subject" value="<?=htmlspecialchars($q_data['subject']);?>" placeholder="Spam Quarantine Notification">
- </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="sender"><span class="glyphicon glyphicon-copy"></span> <?=$lang['admin']['quarantine_bcc'];?></label>
+ <div class="col-sm-8">
+ <input type="email" class="form-control" name="bcc" value="<?=htmlspecialchars($q_data['bcc']);?>" placeholder="">
</div>
</div>
<hr>
- <div class="row">
- <div class="col-sm-12">
- <legend data-target="#quarantine_template" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
- <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['quarantine_notification_html'];?>
- </legend>
- <div id="quarantine_template" class="collapse" >
- <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="html_tmpl"><?=$q_data['html_tmpl'];?></textarea>
- </div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="sender"><?=$lang['admin']['quarantine_notification_sender'];?>:</label>
+ <div class="col-sm-8">
+ <input type="email" class="form-control" name="sender" value="<?=htmlspecialchars($q_data['sender']);?>" placeholder="quarantine@localhost">
</div>
</div>
- <div class="row">
- <div class="col-sm-6">
- <div class="form-group">
- <label for="release_format"><?=$lang['admin']['quarantine_release_format'];?>:</label>
- <select data-width="100%" name="release_format" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
- <option <?=($q_data['release_format'] == 'raw') ? 'selected' : null;?> value="raw"><?=$lang['admin']['quarantine_release_format_raw'];?></option>
- <option <?=($q_data['release_format'] == 'attachment') ? 'selected' : null;?> value="attachment"><?=$lang['admin']['quarantine_release_format_att'];?></option>
- </select>
- </div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="subject"><?=$lang['admin']['quarantine_notification_subject'];?>:</label>
+ <div class="col-sm-8">
+ <input type="text" class="form-control" name="subject" value="<?=htmlspecialchars($q_data['subject']);?>" placeholder="Spam Quarantine Notification">
</div>
- <div class="col-sm-6">
- <div class="form-group">
- <label for="exclude_domains"><?=$lang['admin']['quarantine_exclude_domains'];?>:</label><br />
- <select data-width="100%" name="exclude_domains" class="selectpicker" title="<?=$lang['tfa']['select'];?>" multiple>
- <?php
- foreach (array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')) as $domain):
- ?>
- <option <?=(in_array($domain, $q_data['exclude_domains'])) ? 'selected' : null;?>><?=htmlspecialchars($domain);?></option>
- <?php
- endforeach;
- ?>
- </select>
- </div>
+ </div>
+ <hr>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="release_format"><?=$lang['admin']['quarantine_release_format'];?>:</label>
+ <div class="col-sm-8">
+ <select data-width="100%" name="release_format" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
+ <option <?=($q_data['release_format'] == 'raw') ? 'selected' : null;?> value="raw"><?=$lang['admin']['quarantine_release_format_raw'];?></option>
+ <option <?=($q_data['release_format'] == 'attachment') ? 'selected' : null;?> value="attachment"><?=$lang['admin']['quarantine_release_format_att'];?></option>
+ </select>
</div>
</div>
+ <div class="form-group">
+ <label class="col-sm-4 control-label" for="exclude_domains"><?=$lang['admin']['quarantine_exclude_domains'];?>:</label><br />
+ <div class="col-sm-8">
+ <select data-width="100%" name="exclude_domains" class="selectpicker" title="<?=$lang['tfa']['select'];?>" multiple>
+ <?php
+ foreach (array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')) as $domain):
+ ?>
+ <option <?=(in_array($domain, $q_data['exclude_domains'])) ? 'selected' : null;?>><?=htmlspecialchars($domain);?></option>
+ <?php
+ endforeach;
+ ?>
+ </select>
+ </div>
+ </div>
+ <hr>
+ <legend data-target="#quarantine_template" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
+ <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['quarantine_notification_html'];?>
+ </legend>
+ <div id="quarantine_template" class="collapse" >
+ <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="40" name="html_tmpl"><?=$q_data['html_tmpl'];?></textarea>
+ </div>
<button class="btn btn-sm btn-success" data-action="edit_selected" data-item="self" data-id="quarantine" data-api-url='edit/quarantine' data-api-attr='{"action":"settings"}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
</form>
</div>
diff --git a/data/web/css/site/admin.css b/data/web/css/site/admin.css
index 76246669..81fe98c3 100644
--- a/data/web/css/site/admin.css
+++ b/data/web/css/site/admin.css
@@ -70,3 +70,6 @@ table tbody tr {
table tbody tr td input[type="checkbox"] {
cursor: pointer;
}
+#quarantine_template {
+ margin:20px;
+}
\ No newline at end of file
diff --git a/data/web/inc/functions.quarantine.inc.php b/data/web/inc/functions.quarantine.inc.php
index b14dd643..77498e9c 100644
--- a/data/web/inc/functions.quarantine.inc.php
+++ b/data/web/inc/functions.quarantine.inc.php
@@ -307,6 +307,12 @@ function quarantine($_action, $_data = null) {
else {
$bcc = $_data['bcc'];
}
+ if (!filter_var($_data['redirect'], FILTER_VALIDATE_EMAIL)) {
+ $redirect = '';
+ }
+ else {
+ $redirect = $_data['redirect'];
+ }
if (!filter_var($_data['sender'], FILTER_VALIDATE_EMAIL)) {
$sender = '';
}
@@ -326,6 +332,7 @@ function quarantine($_action, $_data = null) {
$redis->Set('Q_RELEASE_FORMAT', $release_format);
$redis->Set('Q_SENDER', $sender);
$redis->Set('Q_BCC', $bcc);
+ $redis->Set('Q_REDIRECT', $redirect);
$redis->Set('Q_SUBJ', $subject);
$redis->Set('Q_HTML', $html);
}
@@ -793,6 +800,7 @@ function quarantine($_action, $_data = null) {
$settings['subject'] = $redis->Get('Q_SUBJ');
$settings['sender'] = $redis->Get('Q_SENDER');
$settings['bcc'] = $redis->Get('Q_BCC');
+ $settings['redirect'] = $redis->Get('Q_REDIRECT');
$settings['html_tmpl'] = htmlspecialchars($redis->Get('Q_HTML'));
if (empty($settings['html_tmpl'])) {
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl"));
diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json
index c5757825..92d4633c 100644
--- a/data/web/lang/lang.de.json
+++ b/data/web/lang/lang.de.json
@@ -223,6 +223,7 @@
"quarantine_notification_html": "Benachrichtigungs-E-Mail Inhalt:<br><small>Leer lassen, um Standard-Template wiederherzustellen.</small>",
"quarantine_notification_sender": "Benachrichtigungs-E-Mail Absender",
"quarantine_notification_subject": "Benachrichtigungs-E-Mail Betreff",
+ "quarantine_redirect": "<b>Alle</b> Benachrichtigungen an folgendes Postfach umleiten:<br><small>Leer bedeutet deaktiviert. <b>Unsignierte, ungeprüfte E-Mail. Sollte nur intern zugestellt werden.</b></small>",
"quarantine_release_format": "Format freigegebener Mails",
"quarantine_release_format_att": "Als Anhang",
"quarantine_release_format_raw": "Unverändertes Original",
@@ -736,7 +737,7 @@
"check_hash": "Checksumme auf VirusTotal suchen",
"confirm_delete": "Bestätigen Sie die Löschung dieses Elements.",
"danger": "Gefahr",
- "disabled_by_config": "Die derzeitige Konfiguration deaktiviert die Funktion des Quarantäne-Systems.",
+ "disabled_by_config": "Die derzeitige Konfiguration deaktiviert die Funktion des Quarantäne-Systems. Zur Funktion muss eine Anzahl an Rückhaltungen pro Mailbox sowie ein Limit für die maximale Größe pro Element definiert werden.",
"download_eml": "Herunterladen (.eml)",
"empty": "Keine Einträge",
"high_danger": "Hohe Gefahr",
diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json
index 94a5effa..348a643e 100644
--- a/data/web/lang/lang.en.json
+++ b/data/web/lang/lang.en.json
@@ -222,6 +222,7 @@
"quarantine_notification_html": "Notification email template:<br><small>Leave empty to restore default template.</small>",
"quarantine_notification_sender": "Notification email sender",
"quarantine_notification_subject": "Notification email subject",
+ "quarantine_redirect": "<b>Redirect all notifications</b> to this recipient:<br><small>Leave empty to disable. <b>Unsigned, unchecked mail. Should be delivered internally only.</b></small>",
"quarantine_release_format": "Format of released items",
"quarantine_release_format_att": "As attachment",
"quarantine_release_format_raw": "Unmodified original",
@@ -736,7 +737,7 @@
"check_hash": "Search file hash @ VT",
"confirm_delete": "Confirm the deletion of this element.",
"danger": "Danger",
- "disabled_by_config": "The current system configuration disables the quarantine functionality.",
+ "disabled_by_config": "The current system configuration disables the quarantine functionality. Please set \"retentions per mailbox\" and a \"maximum size\" for quarantine elements.",
"download_eml": "Download (.eml)",
"empty": "No results",
"high_danger": "High",
diff --git a/docker-compose.yml b/docker-compose.yml
index 99743924..9c77b25d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -193,7 +193,7 @@ services:
- sogo
dovecot-mailcow:
- image: mailcow/dovecot:1.126
+ image: mailcow/dovecot:1.127
depends_on:
- mysql-mailcow
dns: