Fix: Mailbox Stats über Dovecot mit config/mailpool.php
parent
878dae8876
commit
a25de8c7b7
|
|
@ -16,7 +16,6 @@ class UpdateMailboxStats extends Command
|
||||||
{
|
{
|
||||||
$q = MailUser::query()
|
$q = MailUser::query()
|
||||||
->where('is_active', true)
|
->where('is_active', true)
|
||||||
// sichere Filter: E-Mail vorhanden und enthält genau ein "@"
|
|
||||||
->whereNotNull('email')
|
->whereNotNull('email')
|
||||||
->where('email', 'like', '%@%');
|
->where('email', 'like', '%@%');
|
||||||
|
|
||||||
|
|
@ -33,14 +32,14 @@ class UpdateMailboxStats extends Command
|
||||||
foreach ($users as $u) {
|
foreach ($users as $u) {
|
||||||
$email = trim($u->email);
|
$email = trim($u->email);
|
||||||
if (!preg_match('/^[^@\s]+@[^@\s]+\.[^@\s]+$/', $email)) {
|
if (!preg_match('/^[^@\s]+@[^@\s]+\.[^@\s]+$/', $email)) {
|
||||||
// still und leise überspringen – kein „Überspringe @“ mehr
|
// ungültig → überspringen
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[$local, $domain] = explode('@', $email, 2);
|
[$local, $domain] = explode('@', $email, 2);
|
||||||
$maildir = "/var/mail/vhosts/{$domain}/{$local}";
|
$maildir = "/var/mail/vhosts/{$domain}/{$local}";
|
||||||
|
|
||||||
// 1) Größe in Bytes (rekursiv; ohne "du")
|
// 1) Größe (rekursiv, ohne `du`)
|
||||||
$usedBytes = 0;
|
$usedBytes = 0;
|
||||||
if (is_dir($maildir)) {
|
if (is_dir($maildir)) {
|
||||||
$it = new RecursiveIteratorIterator(
|
$it = new RecursiveIteratorIterator(
|
||||||
|
|
@ -53,29 +52,17 @@ class UpdateMailboxStats extends Command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Message-Count = Dateien in cur/ + new/
|
// 2) Nachrichtenzahl – bevorzugt via doveadm (sudo -u vmail), Fallback: Dateien zählen
|
||||||
$messageCount = 0;
|
$messageCount = $this->messageCountViaDoveadm($email);
|
||||||
foreach (['cur', 'new'] as $sub) {
|
if ($messageCount === null) {
|
||||||
$dir = "{$maildir}/{$sub}";
|
$messageCount = $this->messageCountViaFilesystem($maildir);
|
||||||
if (is_dir($dir)) {
|
|
||||||
$dh = opendir($dir);
|
|
||||||
if ($dh) {
|
|
||||||
while (($fn = readdir($dh)) !== false) {
|
|
||||||
// echte Maildir-Dateien haben keinen führenden Punkt
|
|
||||||
if ($fn !== '.' && $fn !== '..' && $fn[0] !== '.') {
|
|
||||||
$messageCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir($dh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update DB
|
// Update DB
|
||||||
$u->forceFill([
|
$u->forceFill([
|
||||||
'used_bytes' => $usedBytes,
|
'used_bytes' => $usedBytes,
|
||||||
'message_count' => $messageCount,
|
'message_count' => (int) $messageCount,
|
||||||
'stats_refreshed_at'=> now(),
|
'stats_refreshed_at' => now(),
|
||||||
])->save();
|
])->save();
|
||||||
|
|
||||||
$this->line(sprintf(
|
$this->line(sprintf(
|
||||||
|
|
@ -89,4 +76,61 @@ class UpdateMailboxStats extends Command
|
||||||
$this->info('Mailbox-Statistiken aktualisiert.');
|
$this->info('Mailbox-Statistiken aktualisiert.');
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt die Anzahl der Nachrichten in INBOX über doveadm als vmail (sudo).
|
||||||
|
* Gibt int bei Erfolg, oder null bei Fehlern zurück.
|
||||||
|
*/
|
||||||
|
private function messageCountViaDoveadm(string $email): ?int
|
||||||
|
{
|
||||||
|
// bevorzugtes Format: tabellarisch → "INBOX\t123"
|
||||||
|
$cmd = sprintf(
|
||||||
|
"sudo -n -u vmail /usr/bin/doveadm -f tab mailbox status -u %s messages INBOX 2>/dev/null",
|
||||||
|
escapeshellarg($email)
|
||||||
|
);
|
||||||
|
$out = trim((string) shell_exec($cmd));
|
||||||
|
|
||||||
|
if ($out === '') {
|
||||||
|
// Fallback auf normales Format: "messages=123"
|
||||||
|
$cmd2 = sprintf(
|
||||||
|
"sudo -n -u vmail /usr/bin/doveadm mailbox status -u %s messages INBOX 2>/dev/null",
|
||||||
|
escapeshellarg($email)
|
||||||
|
);
|
||||||
|
$out = trim((string) shell_exec($cmd2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($out === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match "INBOX<TAB>123" oder "messages=123"
|
||||||
|
if (preg_match('/\t(\d+)\s*$/', $out, $m) || preg_match('/messages=(\d+)/', $out, $m)) {
|
||||||
|
return (int) $m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fallback: Zählt Dateien in cur/ + new/ (Maildir).
|
||||||
|
*/
|
||||||
|
private function messageCountViaFilesystem(string $maildir): int
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
foreach (['cur', 'new'] as $sub) {
|
||||||
|
$dir = "{$maildir}/{$sub}";
|
||||||
|
if (is_dir($dir) && is_readable($dir)) {
|
||||||
|
$dh = opendir($dir);
|
||||||
|
if ($dh) {
|
||||||
|
while (($fn = readdir($dh)) !== false) {
|
||||||
|
if ($fn !== '.' && $fn !== '..' && $fn[0] !== '.') {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue