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
|
||||
.purs-repl
|
||||
.env
|
||||
qed-mail/node_modules/
|
||||
qed-mail/dist/
|
||||
|
@ -14,5 +14,5 @@
|
||||
"peerDependencies": {
|
||||
"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",
|
||||
"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.",
|
||||
"main": "dist/index.js",
|
||||
"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 },
|
||||
};
|
||||
|
||||
async function checkEmail(email: string): Promise<Result> {
|
||||
async function checkEmail(email: string, {fromAddr}: {fromAddr?: string} = {}): Promise<Result> {
|
||||
const result: Result = { email, ...DEFAULT_RESULT };
|
||||
|
||||
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 smtp = await checkSMTP(email, records[0]!.exchange, 25);
|
||||
const smtp = await checkSMTP(email, records[0]!.exchange, 25, {fromAddr});
|
||||
if (!smtp.valid) {
|
||||
return { ...result, syntax, mx, smtp };
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
import { Client } from "smtp-fetch";
|
||||
import { SMTPResult } from "../types";
|
||||
import { TcpNetConnectOpts } from "net";
|
||||
|
||||
async function checkSMTP(
|
||||
to: string,
|
||||
host: string,
|
||||
port: number,
|
||||
timeout: number = 5000
|
||||
{fromAddr, timeout = 5000}: {timeout?: number, fromAddr?: string} = {},
|
||||
): Promise<SMTPResult> {
|
||||
const c = new Client(host, port);
|
||||
|
||||
try {
|
||||
await c.connect({ timeout });
|
||||
const options: Omit<TcpNetConnectOpts, 'host' | 'port'> = { timeout, localAddress: fromAddr };
|
||||
await c.connect(options);
|
||||
|
||||
await c.mail("");
|
||||
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
|
||||
- effect
|
||||
- either
|
||||
- filterable
|
||||
- foldable-traversable
|
||||
- maybe
|
||||
- newtype
|
||||
- node-os
|
||||
- nullable
|
||||
- prelude
|
||||
- random
|
||||
- strings
|
||||
- tailrec
|
||||
- transformers
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { checkEmail } from 'qed-mail'
|
||||
|
||||
/** @type {(_: string) => () => Promise<import('qed-mail/src/types.js').Result>} */
|
||||
export const checkEmailImpl = s => () => checkEmail(s)
|
||||
/** @type {(email: string) => (addr: string | null) => () => Promise<import('qed-mail/src/types.js').Result>} */
|
||||
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 as Email
|
||||
import Data.Eq.Generic (genericEq)
|
||||
import Data.Filterable (filter)
|
||||
import Data.Foldable (fold)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Int as Int
|
||||
import Data.Maybe (maybe)
|
||||
@ -24,9 +26,12 @@ import Data.Show.Generic (genericShow)
|
||||
import Data.Traversable (for_)
|
||||
import Effect (Effect)
|
||||
import Effect.Aff (Aff, delay)
|
||||
import Effect.Class (liftEffect)
|
||||
import Effect.Random (randomInt)
|
||||
import Node.OS as Node.OS
|
||||
import Type.Function (type ($))
|
||||
|
||||
foreign import checkEmailImpl :: String -> Effect $ Promise $ QEDResult
|
||||
foreign import checkEmailImpl :: String -> Nullable String -> Effect $ Promise $ QEDResult
|
||||
|
||||
data EmailError
|
||||
= EmailUnreachable Email
|
||||
@ -82,8 +87,12 @@ type QEDResult =
|
||||
|
||||
deliverableOnce :: Email -> ExceptT EmailError Aff Email
|
||||
deliverableOnce email' = do
|
||||
let email = Email.toString email'
|
||||
{ reachable, syntax, mx, smtp } <- lift $ Promise.toAffE $ checkEmailImpl email
|
||||
addrs <- liftEffect $ filter (not <<< _.internal) <$> fold <$> Node.OS.networkInterfaces
|
||||
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 mx.valid) $ throwError $ EmailMXInvalid email'
|
||||
when (maybe true Array.null $ Nullable.toMaybe $ mx.mxRecords) $ throwError $ EmailMXNoRecords email'
|
||||
|
Loading…
Reference in New Issue
Block a user