generated from tpl/purs
fix: randomly choose a local address to query from
This commit is contained in:
parent
a91ed02d7d
commit
e304960ee5
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,3 +11,5 @@
|
|||||||
.log
|
.log
|
||||||
.purs-repl
|
.purs-repl
|
||||||
.env
|
.env
|
||||||
|
qed-mail/node_modules/
|
||||||
|
qed-mail/dist/
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": { "qed-mail": "^1.0.2" }
|
"dependencies": { "qed-mail": "./qed-mail/qed-mail-1.0.1@beta-1.tgz" }
|
||||||
}
|
}
|
||||||
|
130
qed-mail/.gitignore
vendored
130
qed-mail/.gitignore
vendored
@ -1,130 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "qed-mail",
|
"name": "qed-mail",
|
||||||
"version": "1.0.1",
|
"version": "1.0.1@beta-1",
|
||||||
"description": "📮 A NodeJS library for checking if an email address exists without sending any email.",
|
"description": "📮 A NodeJS library for checking if an email address exists without sending any email.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
BIN
qed-mail/qed-mail-1.0.1@beta-1.tgz
Normal file
BIN
qed-mail/qed-mail-1.0.1@beta-1.tgz
Normal file
Binary file not shown.
@ -11,7 +11,7 @@ const DEFAULT_RESULT = {
|
|||||||
smtp: { valid: false },
|
smtp: { valid: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
async function checkEmail(email: string): Promise<Result> {
|
async function checkEmail(email: string, {fromAddr}: {fromAddr?: string} = {}): Promise<Result> {
|
||||||
const result: Result = { email, ...DEFAULT_RESULT };
|
const result: Result = { email, ...DEFAULT_RESULT };
|
||||||
|
|
||||||
const syntax = checkSyntax(email);
|
const syntax = checkSyntax(email);
|
||||||
@ -25,7 +25,7 @@ async function checkEmail(email: string): Promise<Result> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const records = mx.mxRecords.sort((a, b) => a.priority - b.priority);
|
const records = mx.mxRecords.sort((a, b) => a.priority - b.priority);
|
||||||
const smtp = await checkSMTP(email, records[0]!.exchange, 25);
|
const smtp = await checkSMTP(email, records[0]!.exchange, 25, {fromAddr});
|
||||||
if (!smtp.valid) {
|
if (!smtp.valid) {
|
||||||
return { ...result, syntax, mx, smtp };
|
return { ...result, syntax, mx, smtp };
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import { Client } from "smtp-fetch";
|
import { Client } from "smtp-fetch";
|
||||||
import { SMTPResult } from "../types";
|
import { SMTPResult } from "../types";
|
||||||
|
import { TcpNetConnectOpts } from "net";
|
||||||
|
|
||||||
async function checkSMTP(
|
async function checkSMTP(
|
||||||
to: string,
|
to: string,
|
||||||
host: string,
|
host: string,
|
||||||
port: number,
|
port: number,
|
||||||
timeout: number = 5000
|
{fromAddr, timeout = 5000}: {timeout?: number, fromAddr?: string} = {},
|
||||||
): Promise<SMTPResult> {
|
): Promise<SMTPResult> {
|
||||||
const c = new Client(host, port);
|
const c = new Client(host, port);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await c.connect({ timeout });
|
const options: Omit<TcpNetConnectOpts, 'host' | 'port'> = { timeout, localAddress: fromAddr };
|
||||||
|
await c.connect(options);
|
||||||
|
|
||||||
await c.mail("");
|
await c.mail("");
|
||||||
await c.rcpt(to);
|
await c.rcpt(to);
|
||||||
|
6416
spago.lock
Normal file
6416
spago.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,11 +6,14 @@ package:
|
|||||||
- bifunctors
|
- bifunctors
|
||||||
- effect
|
- effect
|
||||||
- either
|
- either
|
||||||
|
- filterable
|
||||||
- foldable-traversable
|
- foldable-traversable
|
||||||
- maybe
|
- maybe
|
||||||
- newtype
|
- newtype
|
||||||
|
- node-os
|
||||||
- nullable
|
- nullable
|
||||||
- prelude
|
- prelude
|
||||||
|
- random
|
||||||
- strings
|
- strings
|
||||||
- tailrec
|
- tailrec
|
||||||
- transformers
|
- transformers
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { checkEmail } from 'qed-mail'
|
import { checkEmail } from 'qed-mail'
|
||||||
|
|
||||||
/** @type {(_: string) => () => Promise<import('qed-mail/src/types.js').Result>} */
|
/** @type {(email: string) => (addr: string | null) => () => Promise<import('qed-mail/src/types.js').Result>} */
|
||||||
export const checkEmailImpl = s => () => checkEmail(s)
|
export const checkEmailImpl = s => addr => () => checkEmail(s, {fromAddr: addr || undefined})
|
||||||
|
@ -14,6 +14,8 @@ import Data.Either (Either(..))
|
|||||||
import Data.Email (Email)
|
import Data.Email (Email)
|
||||||
import Data.Email as Email
|
import Data.Email as Email
|
||||||
import Data.Eq.Generic (genericEq)
|
import Data.Eq.Generic (genericEq)
|
||||||
|
import Data.Filterable (filter)
|
||||||
|
import Data.Foldable (fold)
|
||||||
import Data.Generic.Rep (class Generic)
|
import Data.Generic.Rep (class Generic)
|
||||||
import Data.Int as Int
|
import Data.Int as Int
|
||||||
import Data.Maybe (maybe)
|
import Data.Maybe (maybe)
|
||||||
@ -24,9 +26,12 @@ import Data.Show.Generic (genericShow)
|
|||||||
import Data.Traversable (for_)
|
import Data.Traversable (for_)
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Aff (Aff, delay)
|
import Effect.Aff (Aff, delay)
|
||||||
|
import Effect.Class (liftEffect)
|
||||||
|
import Effect.Random (randomInt)
|
||||||
|
import Node.OS as Node.OS
|
||||||
import Type.Function (type ($))
|
import Type.Function (type ($))
|
||||||
|
|
||||||
foreign import checkEmailImpl :: String -> Effect $ Promise $ QEDResult
|
foreign import checkEmailImpl :: String -> Nullable String -> Effect $ Promise $ QEDResult
|
||||||
|
|
||||||
data EmailError
|
data EmailError
|
||||||
= EmailUnreachable Email
|
= EmailUnreachable Email
|
||||||
@ -82,8 +87,12 @@ type QEDResult =
|
|||||||
|
|
||||||
deliverableOnce :: Email -> ExceptT EmailError Aff Email
|
deliverableOnce :: Email -> ExceptT EmailError Aff Email
|
||||||
deliverableOnce email' = do
|
deliverableOnce email' = do
|
||||||
let email = Email.toString email'
|
addrs <- liftEffect $ filter (not <<< _.internal) <$> fold <$> Node.OS.networkInterfaces
|
||||||
{ reachable, syntax, mx, smtp } <- lift $ Promise.toAffE $ checkEmailImpl email
|
chosen <- liftEffect $ randomInt 0 (Array.length addrs - 1)
|
||||||
|
let
|
||||||
|
addr = _.address <$> Array.index addrs chosen
|
||||||
|
email = Email.toString email'
|
||||||
|
{ reachable, syntax, mx, smtp } <- lift $ Promise.toAffE $ checkEmailImpl email (Nullable.toNullable addr)
|
||||||
when (not syntax.valid) $ throwError $ EmailSyntaxInvalid email'
|
when (not syntax.valid) $ throwError $ EmailSyntaxInvalid email'
|
||||||
when (not mx.valid) $ throwError $ EmailMXInvalid email'
|
when (not mx.valid) $ throwError $ EmailMXInvalid email'
|
||||||
when (maybe true Array.null $ Nullable.toMaybe $ mx.mxRecords) $ throwError $ EmailMXNoRecords email'
|
when (maybe true Array.null $ Nullable.toMaybe $ mx.mxRecords) $ throwError $ EmailMXNoRecords email'
|
||||||
|
Loading…
Reference in New Issue
Block a user