diff --git a/README.md b/README.md index 7ad3e06..f7021a9 100755 --- a/README.md +++ b/README.md @@ -35,22 +35,25 @@ docker run --rm --interactive --tty \ ## API -### POST|GET /api/v1/bounces/hard?email=a-valid@email.com -> Record email as hard bounce - block for 8^7 minutes +### POST|GET /api/v1/bounces/complaint?email=a-valid@email.com +> Record email as soft bounce - block similar to soft bounce -### POST|GET /api/v1/bounces/soft?email=a-valid@email.com -> Record email as soft bounce - block exponentially in multiple of 8^n minutes +Complaint is in between a soft bounce and a hard bounce. It could be because the emailing System scan attachment and detect as a virus, or an actual User complaint with their email Provider. -1. First soft bounce, block for 8 minutes -2. Second soft bounce within 8 minutes, block for 64 minutes -3. Third soft bounce within 64 minutes, block for 512 minutes -4. Forth soft bounce within 512 minutes, block for 4096 minutes ~ 3 days -5. And so on... +### POST|GET /api/v1/bounces/hard?email=a-valid@email.com +> Record email as hard bounce - block for 1 year -### POST|GET /api/v1/bounces/complaint?email=a-valid@email.com -> Record email as soft bounce - block exponentially for 8^3 minutes +### POST|GET /api/v1/bounces/remove?emails=a-invalid@email.com,b-invalid@email.net,c-invalid@email.org +> Bulk remove emails from bounce -Complaint is in between a soft bounce and a hard bounce. It could be because the emailing System scan attachment and detect as a virus, or an actual User complaint with their email Provider. +### POST|GET /api/v1/bounces/soft?email=a-valid@email.com +> Record email as soft bounce - block incremental of 1 day + +1. First soft bounce, block for 1 day +2. Second soft bounce within 1 day, block for 2 days +3. Third soft bounce within 2 day, block for 3 days +4. Forth soft bounce within 3 day, block for 4 days +5. And so on... up to 365 days max ### GET /api/v1/bounces/stat?email=a-valid@email.com > Determine if email is sendable diff --git a/docker-compose.yml b/docker-compose.yml index 6397321..c0b121c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,8 @@ services: image: php:8.2-apache restart: always healthcheck: - test: ["CMD-SHELL", "curl -s http://localhost/ | grep -q OK"] + test: ["CMD-SHELL", "curl -s http://localhost/?purge=true | grep -q +OK"] interval: 30s timeout: 15s retries: 3 diff --git a/src/Controllers/BouncesController.php b/src/Controllers/BouncesController.php index 011050c..e6727de 100644 --- a/src/Controllers/BouncesController.php +++ b/src/Controllers/BouncesController.php @@ -6,7 +6,7 @@ class BouncesController extends BaseController { protected function handleBounce($from, $email, $reason, $increment = 1) { - if (!$this->isValidEmail($email)) { + if (! $this->isValidEmail($email)) { return; } @@ -15,10 +15,6 @@ protected function handleBounce($from, $email, $reason, $increment = 1) $item = new \DB\SQL\Mapper($db, 'bounces'); $item->load(array('email=?', $email)); - if ($increment > 7) { - $$increment = 7; - } - if ($item->dry()) { // insert new $item = new \DB\SQL\Mapper($db, 'bounces'); @@ -38,13 +34,12 @@ protected function handleBounce($from, $email, $reason, $increment = 1) $item->from = $this->getOrDefault('GET.from', $from); $item->count += $increment; - $exp_min = pow(8, $item->count); - - if (is_infinite($exp_min)) { - $exp_min = PHP_INT_MAX; + // max ban 365 days or 1 year + if ($item->count > 365) { + $item->count = 365; } - $exp_at = (new \DateTime())->add(\DateInterval::createFromDateString($exp_min . ' minutes')); + $exp_at = (new \DateTime())->add(\DateInterval::createFromDateString($item->count . ' days')); // echo $exp_at->format('Y-m-d H:i:s'); $item->expired_at = $exp_at->format('Y-m-d H:i:s'); @@ -58,7 +53,8 @@ protected function handleBounce($from, $email, $reason, $increment = 1) */ public function remove() { - $values = explode(',', $this->getOrDefault('GET.emails', '')); + $emails = $this->getOrDefault('GET.emails', ''); + $values = array_map('trim', explode(',', $emails)); $count = count($values); $db = $this->getOrDefault('DB', null); $results = $db->exec( @@ -66,7 +62,6 @@ public function remove() $values ); - $this->json([ 'emails' => $values, 'sendable' => true, @@ -80,7 +75,7 @@ public function remove() public function hard() { $email = $this->getOrDefault('GET.email', null); - $this->handleBounce(null, $email, 'hard|5xx', 7); // 7 is ~ 4 years, 8 ~ 32 years + $this->handleBounce(null, $email, 'hard|5xx', 365); } /** @@ -98,7 +93,7 @@ public function soft() public function complaint() { $email = $this->getOrDefault('GET.email', null); - $this->handleBounce(null, $email, 'complaint', 3); + $this->handleBounce(null, $email, 'complaint'); } /** @@ -124,8 +119,11 @@ public function stat() $http_expire = 20 * 60; if ($item->dry()) { - return $this->json([ - 'throttle' => -1, 'sendable' => true], + return $this->json( + [ + 'throttle' => -1, + 'sendable' => true + ], ['ttl' => $http_expire] ); } @@ -135,7 +133,7 @@ public function stat() $expired_at = \DateTime::createFromFormat("Y-m-d H:i:s", $item->expired_at); $throttle = $expired_at->getTimestamp() - time(); - $this->json([ + return $this->json([ 'throttle' => $throttle, 'sendable' => ($throttle < 1) ], ['ttl' => $http_expire]); @@ -146,11 +144,12 @@ public function stat() */ public function stats() { - $emails = explode(',', $this->getOrDefault('GET.emails', '')); + $emails = $this->getOrDefault('GET.emails', ''); + $values = array_map('trim', explode(',', $emails)); $rst = []; $values = []; - foreach ($emails as $email) { + foreach ($values as $email) { if ($this->isValidEmail($email, true)) { $values[] = $email; } else { @@ -191,7 +190,7 @@ protected function handleNotification($payload) if ($message['bounce']['bounceType'] == 'Permanent') { $bt = 'hard|'; - $bc = 7; // 7 is ~ 4 years, 8 ~ 32 years + $bc = 365; } // handle recipients @@ -202,7 +201,6 @@ protected function handleNotification($payload) // 554 5.4.14 Hop count exceeded - possible mail loop ATTR34 if (isset($item['status']) && $item['status'][0] == '5') { $bt = 'hard|'; - $bc = 4; // 3 days } $this->handleBounce( @@ -220,15 +218,13 @@ protected function handleNotification($payload) $this->handleBounce( $source, $item['emailAddress'], - 'complaint|' . $message['complaint']['complaintFeedbackType'], - 6 // 183 days or about 6 months + 'complaint|' . $message['complaint']['complaintFeedbackType'] ); } else { $this->handleBounce( $source, $item['emailAddress'], - 'complaint', - 3 + 'complaint' ); } } diff --git a/src/Controllers/Index.php b/src/Controllers/Index.php index 7f0c98e..27dd923 100755 --- a/src/Controllers/Index.php +++ b/src/Controllers/Index.php @@ -15,7 +15,7 @@ public function index() 'DELETE FROM bounces WHERE expired_at < CURRENT_TIMESTAMP' ); - return $this->json('OK purged!'); + return $this->json('OK'); } $this->json('OK');