Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
# adonis-email-guard

AdonisJS v5 package for email validation and a DB-backed suppression list.
AdonisJS v7 package for email validation and a DB-backed suppression list.

- Syntax / MX / disposable / spam-trap / optional SMTP RCPT-TO checks
- Suppression CRUD with configurable table name
- Suppression table auto-created on boot (opt-out via config)
- Single IoC binding: `@ioc:Adonis/Addons/EmailGuard`
- Container binding: `emailGuard`

## Requirements

- AdonisJS `^7.0.0`
- `@adonisjs/lucid` `^22.0.0`
- Node.js `>=20.6.0`

## Install

```bash
npm i adonis-email-guard
node ace configure adonis-email-guard
node ace add @ezycourse/adonis-email-guard
```

The configure step copies `config/email-guard.ts` into your app and registers the provider.
This installs the package, copies `config/email_guard.ts` into your app, and
registers the provider in `adonisrc.ts`.

To do it manually:

```bash
npm i @ezycourse/adonis-email-guard
node ace configure @ezycourse/adonis-email-guard
```

## Configuration

`config/email-guard.ts`:
`config/email_guard.ts`:

```ts
import {EmailGuardConfig} from '@ioc:Adonis/Addons/EmailGuard';
import { defineConfig } from '@ezycourse/adonis-email-guard'

const emailGuardConfig: EmailGuardConfig = {
export default defineConfig({
tableName: 'email_suppressions',
autoCreateTable: true,
// connection: 'primary',
Expand All @@ -33,31 +46,35 @@ const emailGuardConfig: EmailGuardConfig = {
},
extraDisposableDomains: [],
extraSpamTrapDomains: [],
};

export default emailGuardConfig;
})
```

## Usage

```ts
import EmailGuard from '@ioc:Adonis/Addons/EmailGuard';
import emailGuard from '@ezycourse/adonis-email-guard/services/main'

// validate only
const v = await EmailGuard.validate('user@gmial.com');
const v = await emailGuard.validate('user@gmial.com')
// v.valid → false, v.suggestion → 'user@gmail.com'

// validate + suppression lookup in one call
const c = await EmailGuard.check('user@example.com', {recordFailures: true});
if (!c.valid || c.suppressed) return; // do not send
const c = await emailGuard.check('user@example.com', { recordFailures: true })
if (!c.valid || c.suppressed) return // do not send

// suppression CRUD
await EmailGuard.suppress('bounce@x.com', 'bounce', 'webhook', {provider: 'postmark'});
await EmailGuard.isSuppressed('bounce@x.com'); // true
await EmailGuard.find('bounce@x.com');
await EmailGuard.list({reason: 'bounce', limit: 50});
await EmailGuard.count({source: 'webhook'});
await EmailGuard.unsuppress('bounce@x.com');
await emailGuard.suppress('bounce@x.com', 'bounce', 'webhook', { provider: 'postmark' })
await emailGuard.isSuppressed('bounce@x.com') // true
await emailGuard.find('bounce@x.com')
await emailGuard.unsuppress('bounce@x.com')
```

You can also resolve it from the container:

```ts
import app from '@adonisjs/core/services/app'

const guard = await app.container.make('emailGuard')
```

## API
Expand All @@ -74,7 +91,8 @@ Returns `{ valid, email, reason?, checks, suggestion?, mxHost? }`.

### `check(email, options?)`

`validate` + suppression lookup. With `recordFailures: true`, failures are inserted into the suppression list with `source: 'validator'`.
`validate` + suppression lookup. With `recordFailures: true`, failures are
inserted into the suppression list with `source: 'validator'`.

### Suppression

Expand All @@ -84,8 +102,6 @@ Returns `{ valid, email, reason?, checks, suggestion?, mxHost? }`.
| `unsuppress(email)` | Delete. Returns `true` if a row was removed. |
| `isSuppressed(email)` | Boolean lookup. |
| `find(email)` | Row or `null`. |
| `list(filters?)` | Filter by `reason`/`source`/`search`, with paging. |
| `count(filters?)` | Same filters, returns a count. |
| `ensureTable()` | Idempotent `CREATE TABLE IF NOT EXISTS`. |

## Suppression table schema
Expand Down
98 changes: 0 additions & 98 deletions adonis-typings/email-guard.ts

This file was deleted.

3 changes: 0 additions & 3 deletions adonis-typings/index.ts

This file was deleted.

13 changes: 13 additions & 0 deletions configure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type Configure from '@adonisjs/core/commands/configure'

import { stubsRoot } from './stubs/main.js'

export async function configure(command: Configure): Promise<void> {
const codemods = await command.createCodemods()

await codemods.makeUsingStub(stubsRoot, 'config/email_guard.stub', {})

await codemods.updateRcFile((rcFile) => {
rcFile.addProvider('@ezycourse/adonis-email-guard/email_guard_provider')
})
}
15 changes: 15 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export { configure } from './configure.js'
export { stubsRoot } from './stubs/main.js'
export { defineConfig } from './src/define_config.js'
export { EmailGuard } from './src/email_guard.js'
export { EmailValidator } from './src/validator.js'
export { SuppressionService } from './src/suppression.js'
export type {
EmailGuardConfig,
EmailGuardService,
EmailValidationResult,
SuppressionReason,
SuppressionRow,
SuppressionSource,
ValidateEmailOptions,
} from './src/types.js'
36 changes: 0 additions & 36 deletions instructions.md

This file was deleted.

20 changes: 0 additions & 20 deletions instructions.ts

This file was deleted.

Loading