Skip to content

Commit

Permalink
update expire time
Browse files Browse the repository at this point in the history
  • Loading branch information
noogen committed Jan 13, 2024
1 parent d94f2c8 commit 3353a4f
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 39 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,25 @@ docker run --rm --interactive --tty \

## API

### POST|GET /api/v1/bounces/hard?email=[email protected]
> Record email as hard bounce - block for 8^7 minutes
### POST|GET /api/v1/bounces/complaint?email=[email protected]
> Record email as soft bounce - block similar to soft bounce
### POST|GET /api/v1/bounces/soft?email=[email protected]
> 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=[email protected]
> 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,[email protected],[email protected]
> 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=[email protected]
> 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=[email protected]
> Determine if email is sendable
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 21 additions & 25 deletions src/Controllers/BouncesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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');
Expand All @@ -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');
Expand All @@ -58,15 +53,15 @@ 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(
"DELETE FROM bounces WHERE email in ( ?".str_repeat(", ?", $count-1).")",
$values
);


$this->json([
'emails' => $values,
'sendable' => true,
Expand All @@ -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);
}

/**
Expand All @@ -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');
}

/**
Expand All @@ -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]
);
}
Expand All @@ -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]);
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -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'
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down

0 comments on commit 3353a4f

Please sign in to comment.