feat: implement exim autoresponder worker

This commit is contained in:
Marek Miklewicz
2026-06-02 20:17:49 +02:00
parent 7493e3f9da
commit d3f2fd69db
5 changed files with 287 additions and 7 deletions
+44 -5
View File
@@ -30,25 +30,64 @@ final class MailboxDirectory
return $out;
}
/** @return array{owner:string,domain:string,mailbox:string,email:string}|null */
public function resolveRecipient(string $email): ?array
{
$email = strtolower(trim($email));
if (!preg_match('/^([A-Za-z0-9._+-]+)@([A-Za-z0-9.-]+)$/', $email, $m)) {
return null;
}
$local = $m[1];
$domain = $m[2];
$owners = $this->domainOwners();
$owner = $owners[$domain] ?? null;
if ($owner === null) {
return null;
}
$passwd = $this->virtualRoot . '/' . $domain . '/passwd';
if (!is_file($passwd)) {
return null;
}
foreach (file($passwd, FILE_IGNORE_NEW_LINES) ?: [] as $line) {
$mailbox = strtolower(trim(strtok($line, ':') ?: ''));
if ($mailbox === $local) {
return ['owner' => $owner, 'domain' => $domain, 'mailbox' => $local, 'email' => $local . '@' . $domain];
}
}
return null;
}
/** @return string[] */
private function domainsForUser(string $username): array
{
$domains = [];
foreach ($this->domainOwners() as $domain => $owner) {
if ($owner === $username) {
$domains[] = $domain;
}
}
sort($domains);
return $domains;
}
/** @return array<string,string> */
private function domainOwners(): array
{
$path = $this->virtualRoot . '/domainowners';
if (!is_file($path)) {
return [];
}
$domains = [];
$owners = [];
foreach (file($path, FILE_IGNORE_NEW_LINES) ?: [] as $line) {
if (!str_contains($line, ':')) {
continue;
}
[$domain, $owner] = array_map('trim', explode(':', $line, 2));
if ($owner !== $username || !preg_match('/^[A-Za-z0-9.-]+$/', $domain)) {
if (!preg_match('/^[A-Za-z0-9.-]+$/', $domain) || !preg_match('/^[A-Za-z0-9._-]+$/', $owner)) {
continue;
}
$domains[] = strtolower($domain);
$owners[strtolower($domain)] = $owner;
}
sort($domains);
return $domains;
return $owners;
}
}