mail: Kontakterreichbarkeit - Formpruefung, Domainpruefung, Einlieferer-Bericht
Vier Punkte aus kontakterreichbarkeit-mx-bounces-2026-09-15.md, ohne Veroeffentlichungssperre: - PlausibleEmailDomain: Domain ohne Endung oder mit Tippfehler-TLD ist ein 422 an der Legacy-API, deterministisch ohne DNS. - email_domain_checks + MailDomainChecker ueber DnsResolver-Schnittstelle (RFC 5321 impliziter MX, RFC 7505 Null MX, Unresolved ist kein Befund), Observer an Company/Contact, Job nach Commit, taeglicher Refresh, mail:check-domains fuer den Bestand. Nie eine Adresssperre aus DNS. - Admin > Reports > Einlieferer-Bericht: tote Adressen aus Sperrliste und Domainbefund, automatisch abgelehnte Meldungen mit Grund, Text zum Kopieren und CSV. Versendet nichts. - EmailBounceKind::Policy: 5.7.x wird protokolliert, zaehlt aber nicht auf den Schwellwert. Statuscode entscheidet vor Diagnosetext. Messung vorab: 6 von 877 API-Domains ohne Zustellweg, eine davon fuer 66 der 151 Ruecklaeufer verantwortlich. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fddfd8a61c
commit
ada41cb067
34 changed files with 1985 additions and 25 deletions
|
|
@ -110,25 +110,26 @@ test('the free-text notice of our own relay is read and never mistaken for an au
|
|||
->and($suppressions->isSuppressed('info@example.org'))->toBeTrue();
|
||||
});
|
||||
|
||||
test('policy rejections and full mailboxes count soft, not hard', function () {
|
||||
test('policy rejections and full mailboxes never count hard', function () {
|
||||
/** @var TestCase $this */
|
||||
// 5.7.1 „Relay access denied": die Adresse existiert, ihr Server nimmt
|
||||
// nur nichts an — erst der Schwellwert sperrt.
|
||||
// nur nichts an — protokollieren, nicht zählen.
|
||||
$result = app(BounceMailProcessor::class)->process(bounceFixture('policy-5.7.1'));
|
||||
|
||||
expect($result['folder'])->toBe(BounceMailProcessor::Processed)
|
||||
->and(EmailBounce::query()->first()->kind)->toBe(EmailBounceKind::Soft)
|
||||
->and(EmailBounce::query()->first()->kind)->toBe(EmailBounceKind::Policy)
|
||||
->and(EmailBounce::query()->first()->reference)->toBe('pm:99:company:7')
|
||||
->and(app(EmailSuppressionService::class)->isSuppressed('pr@example.net'))->toBeFalse();
|
||||
|
||||
$quota = str_replace(
|
||||
['Status: 5.7.1', '554 5.7.1 <pr@example.net>: Relay access denied', '<20260915120000.ABC@'],
|
||||
['Status: 5.0.0', '552 Requested mail action aborted: exceeded storage allocation', '<20260915120001.ABC@'],
|
||||
['Status: 5.2.2', '552 Requested mail action aborted: exceeded storage allocation', '<20260915120001.ABC@'],
|
||||
bounceFixture('policy-5.7.1'),
|
||||
);
|
||||
app(BounceMailProcessor::class)->process($quota);
|
||||
|
||||
expect(EmailBounce::query()->count())->toBe(2)
|
||||
->and(EmailBounce::query()->where('kind', EmailBounceKind::Soft->value)->count())->toBe(1)
|
||||
->and(EmailBounce::query()->where('kind', EmailBounceKind::Hard->value)->count())->toBe(0);
|
||||
});
|
||||
|
||||
|
|
@ -138,3 +139,17 @@ test('the fetch command does nothing without a configured mailbox', function ()
|
|||
|
||||
$this->artisan('mail:fetch-bounces')->expectsOutputToContain('nicht konfiguriert')->assertSuccessful();
|
||||
});
|
||||
|
||||
test('a policy rejection is logged but never counts toward suppression', function () {
|
||||
/** @var TestCase $this */
|
||||
// Vier Richtlinien-Ablehnungen: Der Schwellwert (3) darf sie nicht
|
||||
// erfassen — das Postfach kann einwandfrei existieren.
|
||||
$raw = bounceFixture('policy-5.7.1');
|
||||
|
||||
foreach (range(1, 4) as $i) {
|
||||
app(BounceMailProcessor::class)->process(str_replace('<20260915120000.ABC@', '<2026091512000'.$i.'.ABC@', $raw));
|
||||
}
|
||||
|
||||
expect(EmailBounce::query()->where('kind', EmailBounceKind::Policy->value)->count())->toBe(4)
|
||||
->and(app(EmailSuppressionService::class)->isSuppressed('pr@example.net'))->toBeFalse();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue