[Dovecot] Quota notifications: Allow to send to external address (BCC via mailcow UI)
parent
9c075af2d9
commit
beda649ecf
|
@ -9,6 +9,7 @@ import jinja2
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
import redis
|
import redis
|
||||||
import time
|
import time
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
import html2text
|
import html2text
|
||||||
from subprocess import Popen, PIPE, STDOUT
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
@ -57,6 +58,27 @@ try:
|
||||||
p = Popen(['/usr/lib/dovecot/dovecot-lda', '-d', username, '-o', '"plugin/quota=maildir:User quota:noenforcing"'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
|
p = Popen(['/usr/lib/dovecot/dovecot-lda', '-d', username, '-o', '"plugin/quota=maildir:User quota:noenforcing"'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
|
||||||
p.communicate(input=bytes(msg.as_string(), 'utf-8'))
|
p.communicate(input=bytes(msg.as_string(), 'utf-8'))
|
||||||
|
|
||||||
|
domain = username.split("@")[-1]
|
||||||
|
if domain and r.hget('QW_BCC', domain):
|
||||||
|
bcc_data = json.loads(r.hget('QW_BCC', domain))
|
||||||
|
bcc_rcpts = bcc_data['bcc_rcpts']
|
||||||
|
if bcc_data['active'] == 1:
|
||||||
|
for rcpt in bcc_rcpts:
|
||||||
|
msg = MIMEMultipart('alternative')
|
||||||
|
msg['From'] = username
|
||||||
|
subject = r.get('QW_SUBJ') or "Quota warning"
|
||||||
|
msg['Subject'] = subject + ' (' + username + ')'
|
||||||
|
msg['Date'] = formatdate(localtime = True)
|
||||||
|
text_part = MIMEText(text, 'plain', 'utf-8')
|
||||||
|
html_part = MIMEText(html, 'html', 'utf-8')
|
||||||
|
msg.attach(text_part)
|
||||||
|
msg.attach(html_part)
|
||||||
|
msg['To'] = rcpt
|
||||||
|
server = smtplib.SMTP('postfix', 588, 'quarantine')
|
||||||
|
server.ehlo()
|
||||||
|
server.sendmail(msg['From'], str(rcpt), msg.as_string())
|
||||||
|
server.quit()
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('Failed to send quota notification: %s' % (ex))
|
print('Failed to send quota notification: %s' % (ex))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -69,4 +91,4 @@ except:
|
||||||
try:
|
try:
|
||||||
sys.stderr.close()
|
sys.stderr.close()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
|
@ -104,7 +104,7 @@ table.footable > tbody > tr.footable-empty > th {
|
||||||
}
|
}
|
||||||
.fooicon {
|
.fooicon {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 1px;
|
top: 0px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: "bootstrap-icons" !important;
|
font-family: "bootstrap-icons" !important;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
@ -123,10 +123,10 @@ table.footable > tbody > tr.footable-empty > th {
|
||||||
content: "\f130";
|
content: "\f130";
|
||||||
}
|
}
|
||||||
.fooicon-plus:before {
|
.fooicon-plus:before {
|
||||||
content: "\f64d";
|
content: "\f4fc";
|
||||||
}
|
}
|
||||||
.fooicon-minus:before {
|
.fooicon-minus:before {
|
||||||
content: "\f63b";
|
content: "\f2e8";
|
||||||
}
|
}
|
||||||
.fooicon-search:before {
|
.fooicon-search:before {
|
||||||
content: "\f52a";
|
content: "\f52a";
|
||||||
|
|
|
@ -230,3 +230,9 @@ table.footable>tbody>tr.footable-empty>td {
|
||||||
font-style:italic;
|
font-style:italic;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
.navbar-nav > li {
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
|
.dropdown-menu > li > a {
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
|
@ -83,7 +83,7 @@ $xmpp_status = xmpp_control('status');
|
||||||
<p><?=$lang['debug']['started_at'];?>: <span class="parse_date"><?=$solr_status['status']['dovecot-fts']['startTime'];?></span></p>
|
<p><?=$lang['debug']['started_at'];?>: <span class="parse_date"><?=$solr_status['status']['dovecot-fts']['startTime'];?></span></p>
|
||||||
<p><?=$lang['debug']['last_modified'];?>: <span class="parse_date"><?=$solr_status['status']['dovecot-fts']['index']['lastModified'];?></span></p>
|
<p><?=$lang['debug']['last_modified'];?>: <span class="parse_date"><?=$solr_status['status']['dovecot-fts']['index']['lastModified'];?></span></p>
|
||||||
<p><?=$lang['debug']['size'];?>: <?=$solr_status['status']['dovecot-fts']['index']['size'];?></p>
|
<p><?=$lang['debug']['size'];?>: <?=$solr_status['status']['dovecot-fts']['index']['size'];?></p>
|
||||||
<p><?=$lang['debug']['docs'];?>: <?=$solr_status['status']['dovecot-fts']['index']['numDocs'];?></p>
|
<p><i class="bi bi-file-text"></i> <?=$lang['debug']['docs'];?>: <?=$solr_status['status']['dovecot-fts']['index']['numDocs'];?></p>
|
||||||
<?php
|
<?php
|
||||||
else:
|
else:
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -127,9 +127,9 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<?php } if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])) { ?>
|
<?php } if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])) { ?>
|
||||||
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <i class="bi bi-door-open"></i></a></li>
|
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <i class="bi bi-x-circle"></i></a></li>
|
||||||
<?php } elseif (isset($_SESSION['dual-login'])) { ?>
|
<?php } elseif (isset($_SESSION['dual-login'])) { ?>
|
||||||
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><i class="bi bi-door-open"></i></a></li>
|
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><i class="bi bi-x-circle"></i></a></li>
|
||||||
<?php } if (!preg_match('/y|yes/i', getenv('MASTER'))) { ?>
|
<?php } if (!preg_match('/y|yes/i', getenv('MASTER'))) { ?>
|
||||||
<li class="text-warning slave-info">[ slave ]</li>
|
<li class="text-warning slave-info">[ slave ]</li>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
|
@ -291,7 +291,7 @@ jQuery(function($){
|
||||||
else {
|
else {
|
||||||
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>';
|
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>';
|
||||||
}
|
}
|
||||||
item.action += '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-question-lg"></i> DNS</a></div>';
|
item.action += '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
|
||||||
if (item.backupmx == 1) {
|
if (item.backupmx == 1) {
|
||||||
if (item.relay_unknown_only == 1) {
|
if (item.relay_unknown_only == 1) {
|
||||||
item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
|
item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
|
||||||
|
|
Loading…
Reference in New Issue