This commit is contained in:
quoije
2023-05-10 21:03:22 -04:00
parent ef1b411c12
commit bd732815c7
1304 changed files with 192970 additions and 5407 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
+75
View File
@@ -0,0 +1,75 @@
# Email Validator
[![NPM](https://nodei.co/npm/deep-email-validator.png)](https://nodei.co/npm/deep-email-validator/)
Validates email addresses based on regex, common typos, disposable email blacklists, DNS records and SMTP server response.
- Validates email looks like an email i.e. contains an "@" and a "." to the right of it.
- Validates common typos e.g. example@gmaill.com using [mailcheck](https://github.com/mailcheck/mailcheck).
- Validates email was not generated by disposable email service using [disposable-email-domains](https://github.com/ivolo/disposable-email-domains).
- Validates MX records are present on DNS.
- Validates SMTP server is running.
- Validates mailbox exists on SMTP server.
- Native typescript support.
## Getting Started
Comaptible with nodejs only. Not browser ready.
Install like so
```
npm i deep-email-validator --save
```
or with yarn
```
yarn add deep-email-validator
```
Use like so
```typescript
import validate from 'deep-email-validator'
const main = async () => {
let res = await validate('[email protected]')
// {
// "valid": false,
// "reason": "smtp",
// "validators": {
// "regex": {
// "valid": true
// },
// "typo": {
// "valid": true
// },
// "disposable": {
// "valid": true
// },
// "mx": {
// "valid": true
// },
// "smtp": {
// "valid": false,
// "reason": "Mailbox not found.",
// }
// }
// }
// Can also be called with these default options
await validate({
email: '[email protected]',
sender: '[email protected]',
validateRegex: true,
validateMx: true,
validateTypo: true,
validateDisposable: true,
validateSMTP: true,
})
}
```
[Default options can be found here](https://github.com/mfbx9da4/deep-email-validator/blob/cefb37abc6e42d3a1551d38f9706d4ff538226e5/src/options/options.ts#L1)
+1
View File
@@ -0,0 +1 @@
export declare const checkDisposable: (domain: string) => Promise<string | undefined>;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkDisposable = void 0;
const disposable_email_domains_1 = __importDefault(require("disposable-email-domains"));
const disposableDomains = new Set(disposable_email_domains_1.default);
exports.checkDisposable = (domain) => __awaiter(void 0, void 0, void 0, function* () {
if (disposableDomains.has(domain))
return 'Email was created using a disposable email service';
});
//# sourceMappingURL=disposable.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"disposable.js","sourceRoot":"","sources":["../../src/disposable/disposable.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wFAA8C;AAC9C,MAAM,iBAAiB,GAAgB,IAAI,GAAG,CAAC,kCAAO,CAAC,CAAA;AAE1C,QAAA,eAAe,GAAG,CAC7B,MAAc,EACe,EAAE;IAC/B,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;QAC/B,OAAO,oDAAoD,CAAA;AAC/D,CAAC,CAAA,CAAA"}
+3
View File
@@ -0,0 +1,3 @@
import dns from 'dns';
export declare const getMx: (domain: string) => Promise<dns.MxRecord[]>;
export declare const getBestMx: (domain: string) => Promise<dns.MxRecord | undefined>;
+34
View File
@@ -0,0 +1,34 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBestMx = exports.getMx = void 0;
const dns_1 = __importDefault(require("dns"));
exports.getMx = (domain) => __awaiter(void 0, void 0, void 0, function* () {
return new Promise(r => dns_1.default.resolveMx(domain, (err, addresses) => {
if (err || !addresses)
return r([]);
r(addresses);
}));
});
exports.getBestMx = (domain) => __awaiter(void 0, void 0, void 0, function* () {
const addresses = yield exports.getMx(domain);
let bestIndex = 0;
for (let i = 0; i < addresses.length; i++) {
if (addresses[i].priority < addresses[bestIndex].priority) {
bestIndex = i;
}
}
return addresses[bestIndex];
});
//# sourceMappingURL=dns.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"dns.js","sourceRoot":"","sources":["../../src/dns/dns.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,8CAAqB;AAER,QAAA,KAAK,GAAG,CAAO,MAAc,EAA2B,EAAE;IACrE,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CACrB,aAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE;QACvC,IAAI,GAAG,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,EAAoB,CAAC,CAAA;QACrD,CAAC,CAAC,SAAS,CAAC,CAAA;IACd,CAAC,CAAC,CACH,CAAA;AACH,CAAC,CAAA,CAAA;AAEY,QAAA,SAAS,GAAG,CACvB,MAAc,EACqB,EAAE;IACrC,MAAM,SAAS,GAAG,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,SAAS,GAAG,CAAC,CAAA;IAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACzC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;YACzD,SAAS,GAAG,CAAC,CAAA;SACd;KACF;IAED,OAAO,SAAS,CAAC,SAAS,CAAC,CAAA;AAC7B,CAAC,CAAA,CAAA"}
+5
View File
@@ -0,0 +1,5 @@
import { ValidatorOptions } from './options/options';
import { OutputFormat } from './output/output';
import './types';
export declare function validate(emailOrOptions: string | ValidatorOptions): Promise<OutputFormat>;
export default validate;
+54
View File
@@ -0,0 +1,54 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validate = void 0;
const regex_1 = require("./regex/regex");
const typo_1 = require("./typo/typo");
const dns_1 = require("./dns/dns");
const smtp_1 = require("./smtp/smtp");
const disposable_1 = require("./disposable/disposable");
const options_1 = require("./options/options");
const output_1 = require("./output/output");
require("./types");
function validate(emailOrOptions) {
return __awaiter(this, void 0, void 0, function* () {
const options = options_1.getOptions(emailOrOptions);
const email = options.email;
if (options.validateRegex) {
const regexResponse = regex_1.isEmail(email);
if (regexResponse)
return output_1.createOutput('regex', regexResponse);
}
if (options.validateTypo) {
const typoResponse = yield typo_1.checkTypo(email, options.additionalTopLevelDomains);
if (typoResponse)
return output_1.createOutput('typo', typoResponse);
}
const domain = email.split('@')[1];
if (options.validateDisposable) {
const disposableResponse = yield disposable_1.checkDisposable(domain);
if (disposableResponse)
return output_1.createOutput('disposable', disposableResponse);
}
if (options.validateMx) {
const mx = yield dns_1.getBestMx(domain);
if (!mx)
return output_1.createOutput('mx', 'MX record not found');
if (options.validateSMTP) {
return smtp_1.checkSMTP(options.sender, email, mx.exchange);
}
}
return output_1.createOutput();
});
}
exports.validate = validate;
exports.default = validate;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yCAAuC;AACvC,sCAAuC;AACvC,mCAAqC;AACrC,sCAAuC;AACvC,wDAAyD;AACzD,+CAAgE;AAChE,4CAA4D;AAC5D,mBAAgB;AAEhB,SAAsB,QAAQ,CAC5B,cAAyC;;QAEzC,MAAM,OAAO,GAAG,oBAAU,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAE3B,IAAI,OAAO,CAAC,aAAa,EAAE;YACzB,MAAM,aAAa,GAAG,eAAO,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,aAAa;gBAAE,OAAO,qBAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;SAC/D;QAED,IAAI,OAAO,CAAC,YAAY,EAAE;YACxB,MAAM,YAAY,GAAG,MAAM,gBAAS,CAAC,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAA;YAC9E,IAAI,YAAY;gBAAE,OAAO,qBAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;SAC5D;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QAElC,IAAI,OAAO,CAAC,kBAAkB,EAAE;YAC9B,MAAM,kBAAkB,GAAG,MAAM,4BAAe,CAAC,MAAM,CAAC,CAAA;YACxD,IAAI,kBAAkB;gBACpB,OAAO,qBAAY,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;SACxD;QAED,IAAI,OAAO,CAAC,UAAU,EAAE;YACtB,MAAM,EAAE,GAAG,MAAM,eAAS,CAAC,MAAM,CAAC,CAAA;YAClC,IAAI,CAAC,EAAE;gBAAE,OAAO,qBAAY,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAA;YACzD,IAAI,OAAO,CAAC,YAAY,EAAE;gBACxB,OAAO,gBAAS,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAA;aACrD;SACF;QAED,OAAO,qBAAY,EAAE,CAAA;IACvB,CAAC;CAAA;AAjCD,4BAiCC;AAED,kBAAe,QAAQ,CAAA"}
+19
View File
@@ -0,0 +1,19 @@
declare type Options = {
sender: string;
validateRegex: boolean;
validateMx: boolean;
validateTypo: boolean;
validateDisposable: boolean;
validateSMTP: boolean;
};
declare type MailCheckOptions = {
additionalTopLevelDomains?: string[];
};
export declare type ValidatorOptions = Partial<Options> & {
email: string;
} & MailCheckOptions;
declare type ValidatorOptionsFinal = Options & {
email: string;
} & MailCheckOptions;
export declare function getOptions(emailOrOptions: string | ValidatorOptions): ValidatorOptionsFinal;
export {};
+24
View File
@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOptions = void 0;
const defaultOptions = {
email: '[email protected]',
sender: '[email protected]',
validateRegex: true,
validateMx: true,
validateTypo: true,
validateDisposable: true,
validateSMTP: true,
};
function getOptions(emailOrOptions) {
let options = defaultOptions;
if (typeof emailOrOptions === 'string') {
options = Object.assign(Object.assign({}, options), { email: emailOrOptions });
}
else {
options = Object.assign(Object.assign({}, options), emailOrOptions);
}
return options;
}
exports.getOptions = getOptions;
//# sourceMappingURL=options.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/options/options.ts"],"names":[],"mappings":";;;AAAA,MAAM,cAAc,GAA0B;IAC5C,KAAK,EAAE,kBAAkB;IACzB,MAAM,EAAE,kBAAkB;IAC1B,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,IAAI;IAClB,kBAAkB,EAAE,IAAI;IACxB,YAAY,EAAE,IAAI;CACnB,CAAA;AAkBD,SAAgB,UAAU,CACxB,cAAyC;IAEzC,IAAI,OAAO,GAA0B,cAAc,CAAA;IAEnD,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE;QACtC,OAAO,mCAAQ,OAAO,KAAE,KAAK,EAAE,cAAc,GAAE,CAAA;KAChD;SAAM;QACL,OAAO,mCAAQ,OAAO,GAAK,cAAc,CAAE,CAAA;KAC5C;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAXD,gCAWC"}
+14
View File
@@ -0,0 +1,14 @@
import { ElementType } from '../types';
declare const OrderedLevels: readonly ["regex", "typo", "disposable", "mx", "smtp"];
export declare type SubOutputFormat = {
valid: boolean;
reason?: string;
};
declare type Level = ElementType<typeof OrderedLevels>;
export declare type OutputFormat = SubOutputFormat & {
validators: {
[K in Level]?: SubOutputFormat;
};
};
export declare const createOutput: (failLevel?: "regex" | "typo" | "disposable" | "mx" | "smtp" | undefined, failReason?: string | undefined) => OutputFormat;
export {};
+24
View File
@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOutput = void 0;
const OrderedLevels = ['regex', 'typo', 'disposable', 'mx', 'smtp'];
exports.createOutput = (failLevel, failReason) => {
const out = { valid: true, validators: {} };
if (failLevel) {
out.reason = failLevel;
out.valid = false;
}
let valid = true;
for (let i = 0; i < OrderedLevels.length; i++) {
const level = OrderedLevels[i];
const levelOut = { valid };
if (level === failLevel) {
valid = false;
levelOut.valid = false;
levelOut.reason = failReason;
}
out.validators[level] = levelOut;
}
return out;
};
//# sourceMappingURL=output.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/output/output.ts"],"names":[],"mappings":";;;AAEA,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,CAAU,CAAA;AAc/D,QAAA,YAAY,GAAG,CAC1B,SAAiB,EACjB,UAAmB,EACL,EAAE;IAChB,MAAM,GAAG,GAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;IACzD,IAAI,SAAS,EAAE;QACb,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;QACtB,GAAG,CAAC,KAAK,GAAG,KAAK,CAAA;KAClB;IACD,IAAI,KAAK,GAAG,IAAI,CAAA;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,QAAQ,GAAoB,EAAE,KAAK,EAAE,CAAA;QAC3C,IAAI,KAAK,KAAK,SAAS,EAAE;YACvB,KAAK,GAAG,KAAK,CAAA;YACb,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAA;YACtB,QAAQ,CAAC,MAAM,GAAG,UAAU,CAAA;SAC7B;QACD,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAA;KACjC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
+1
View File
@@ -0,0 +1 @@
export declare const isEmail: (email: string) => string | undefined;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEmail = void 0;
exports.isEmail = (email) => {
email = (email || '').trim();
if (email.length === 0) {
return 'Email not provided';
}
const split = email.split('@');
if (split.length < 2) {
return 'Email does not contain "@".';
}
else {
const [domain] = split.slice(-1);
if (domain.indexOf('.') === -1) {
return 'Must contain a "." after the "@".';
}
}
};
//# sourceMappingURL=regex.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"regex.js","sourceRoot":"","sources":["../../src/regex/regex.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,CAAC,KAAa,EAAsB,EAAE;IAC3D,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACtB,OAAO,oBAAoB,CAAA;KAC5B;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QACpB,OAAO,6BAA6B,CAAA;KACrC;SAAM;QACL,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAChC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;YAC9B,OAAO,mCAAmC,CAAA;SAC3C;KACF;AACH,CAAC,CAAA"}
+25
View File
@@ -0,0 +1,25 @@
/// <reference types="node" />
export declare const ErrorCodes: {
211: string;
214: string;
220: string;
221: string;
250: string;
251: string;
354: string;
421: string;
450: string;
451: string;
452: string;
500: string;
501: string;
502: string;
503: string;
504: string;
550: string;
551: string;
552: string;
553: string;
554: string;
};
export declare const hasCode: (message: Buffer, code: keyof typeof ErrorCodes) => boolean;
+30
View File
@@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasCode = exports.ErrorCodes = void 0;
exports.ErrorCodes = {
211: 'SMTP Error: A system status or help reply.',
214: 'SMTP Error: Help Message.',
220: 'SMTP Error: The server is ready.',
221: 'SMTP Error: The server is ending the conversation.',
250: 'SMTP Error: The requested action was completed.',
251: 'SMTP Error: The specified user is not local, but the server will forward the mail message.',
354: 'SMTP Error: This is a reply to the DATA command. After getting this, start sending the body of the mail message, ending with "\r\n.\r\n."',
421: 'SMTP Error: The mail server will be shut down. Save the mail message and try again later.',
450: 'SMTP Error: The mailbox that you are trying to reach is busy. Wait a little while and try again.',
451: 'SMTP Error: The requested action was not done. Some error occurmiles in the mail server.',
452: 'SMTP Error: The requested action was not done. The mail server ran out of system storage.',
500: 'SMTP Error: The last command contained a syntax error or the command line was too long.',
501: 'SMTP Error: The parameters or arguments in the last command contained a syntax error.',
502: 'SMTP Error: The mail server has not implemented the last command.',
503: 'SMTP Error: The last command was sent out of sequence. For example, you might have sent DATA before sending RECV.',
504: 'SMTP Error: One of the parameters of the last command has not been implemented by the server.',
550: "SMTP Error: The mailbox that you are trying to reach can't be found or you don't have access rights.",
551: 'SMTP Error: The specified user is not local; part of the text of the message will contain a forwarding address.',
552: 'SMTP Error: The mailbox that you are trying to reach has run out of space. Store the message and try again tomorrow or in a few days-after the user gets a chance to delete some messages.',
553: 'SMTP Error: The mail address that you specified was not syntactically correct.',
554: 'SMTP Error: The mail transaction has failed for unknown causes.',
};
exports.hasCode = (message, code) => {
return message.indexOf(`${code}`) === 0 || message.indexOf(`${code}\n`) > -1;
};
//# sourceMappingURL=errorCodes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"errorCodes.js","sourceRoot":"","sources":["../../src/smtp/errorCodes.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG;IACxB,GAAG,EAAE,4CAA4C;IACjD,GAAG,EAAE,2BAA2B;IAChC,GAAG,EAAE,kCAAkC;IACvC,GAAG,EAAE,oDAAoD;IACzD,GAAG,EAAE,iDAAiD;IACtD,GAAG,EAAE,4FAA4F;IACjG,GAAG,EAAE,2IAA2I;IAChJ,GAAG,EAAE,2FAA2F;IAChG,GAAG,EAAE,kGAAkG;IACvG,GAAG,EAAE,0FAA0F;IAC/F,GAAG,EAAE,2FAA2F;IAChG,GAAG,EAAE,yFAAyF;IAC9F,GAAG,EAAE,uFAAuF;IAC5F,GAAG,EAAE,mEAAmE;IACxE,GAAG,EAAE,mHAAmH;IACxH,GAAG,EAAE,+FAA+F;IACpG,GAAG,EAAE,sGAAsG;IAC3G,GAAG,EAAE,iHAAiH;IACtH,GAAG,EAAE,4LAA4L;IACjM,GAAG,EAAE,gFAAgF;IACrF,GAAG,EAAE,iEAAiE;CACvE,CAAA;AAEY,QAAA,OAAO,GAAG,CACrB,OAAe,EACf,IAA6B,EACpB,EAAE;IACX,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9E,CAAC,CAAA"}
+2
View File
@@ -0,0 +1,2 @@
import { OutputFormat } from '../output/output';
export declare const checkSMTP: (sender: string, recipient: string, exchange: string) => Promise<OutputFormat>;
+96
View File
@@ -0,0 +1,96 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkSMTP = void 0;
const net_1 = __importDefault(require("net"));
const output_1 = require("../output/output");
const errorCodes_1 = require("./errorCodes");
const log = (...args) => {
if (process.env.DEBUG === 'true') {
console.log(...args);
}
};
exports.checkSMTP = (sender, recipient, exchange) => __awaiter(void 0, void 0, void 0, function* () {
const timeout = 1000 * 10; // 10 seconds
return new Promise(r => {
let receivedData = false;
const socket = net_1.default.createConnection(25, exchange);
socket.setEncoding('ascii');
socket.setTimeout(timeout);
socket.on('error', error => {
log('error', error);
socket.emit('fail', error);
});
socket.on('close', hadError => {
if (!receivedData && !hadError) {
socket.emit('fail', 'Mail server closed connection without sending any data.');
}
});
socket.once('fail', msg => {
r(output_1.createOutput('smtp', msg));
if (socket.writable && !socket.destroyed) {
socket.write(`quit\r\n`);
socket.end();
socket.destroy();
}
});
socket.on('success', () => {
if (socket.writable && !socket.destroyed) {
socket.write(`quit\r\n`);
socket.end();
socket.destroy();
}
r(output_1.createOutput());
});
const commands = [
`helo ${exchange}\r\n`,
`mail from: <${sender}>\r\n`,
`rcpt to: <${recipient}>\r\n`,
];
let i = 0;
socket.on('next', () => {
if (i < 3) {
if (socket.writable) {
socket.write(commands[i++]);
}
else {
socket.emit('fail', 'SMTP communication unexpectedly closed.');
}
}
else {
socket.emit('success');
}
});
socket.on('timeout', () => {
socket.emit('fail', 'Timeout');
});
socket.on('connect', () => {
socket.on('data', msg => {
receivedData = true;
log('data', msg);
if (errorCodes_1.hasCode(msg, 220) || errorCodes_1.hasCode(msg, 250)) {
socket.emit('next', msg);
}
else if (errorCodes_1.hasCode(msg, 550)) {
socket.emit('fail', 'Mailbox not found.');
}
else {
const [code] = Object.typedKeys(errorCodes_1.ErrorCodes).filter(x => errorCodes_1.hasCode(msg, x));
socket.emit('fail', errorCodes_1.ErrorCodes[code] || 'Unrecognized SMTP response.');
}
});
});
});
});
//# sourceMappingURL=smtp.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"smtp.js","sourceRoot":"","sources":["../../src/smtp/smtp.ts"],"names":[],"mappings":"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"}
+6
View File
@@ -0,0 +1,6 @@
declare global {
interface ObjectConstructor {
typedKeys<T>(o: T): Array<keyof T>;
}
}
export declare type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;
+4
View File
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
Object.typedKeys = Object.keys;
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AAKA,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,IAAW,CAAA"}
+1
View File
@@ -0,0 +1 @@
export declare const checkTypo: (email: string, additionalTLDs?: string[] | undefined) => Promise<string | undefined>;
+35
View File
@@ -0,0 +1,35 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkTypo = void 0;
const mailcheck_1 = __importDefault(require("mailcheck"));
exports.checkTypo = (email, additionalTLDs) => __awaiter(void 0, void 0, void 0, function* () {
return new Promise(r => {
let topLevelDomains = undefined;
if (additionalTLDs && additionalTLDs.length > 0) {
topLevelDomains = [...mailcheck_1.default.defaultTopLevelDomains, ...additionalTLDs];
}
mailcheck_1.default.run({
email,
topLevelDomains: topLevelDomains,
suggested: (suggestion) => {
r(`Likely typo, suggested email: ${suggestion.full}`);
},
empty: function () {
r();
},
});
});
});
//# sourceMappingURL=typo.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"typo.js","sourceRoot":"","sources":["../../src/typo/typo.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,0DAAiC;AAQpB,QAAA,SAAS,GAAG,CAAO,KAAa,EAAE,cAAyB,EAA+B,EAAE;IACvG,OAAA,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;QAEd,IAAI,eAAe,GAAG,SAAS,CAAA;QAC/B,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;YAC7C,eAAe,GAAG,CAAC,GAAG,mBAAS,CAAC,sBAAsB,EAAE,GAAG,cAAc,CAAC,CAAA;SAC7E;QACD,mBAAS,CAAC,GAAG,CAAC;YACZ,KAAK;YACL,eAAe,EAAE,eAAe;YAChC,SAAS,EAAE,CAAC,UAA0B,EAAE,EAAE;gBACxC,CAAC,CAAC,iCAAiC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAA;YACvD,CAAC;YACD,KAAK,EAAE;gBACL,CAAC,EAAE,CAAA;YACL,CAAC;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;EAAA,CAAA"}
+63
View File
@@ -0,0 +1,63 @@
{
"name": "deep-email-validator",
"version": "0.1.21",
"files": [
"dist/**/*"
],
"description": "Validates emails based on regex, common typos, disposable email blacklists, DNS records and SMTP server response.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/mfbx9da4/deep-email-validator"
},
"author": "David Alberto Adler",
"license": "MIT",
"keywords": [
"email-validation",
"email-typos",
"email-regex",
"disposable-emails",
"smtp",
"mx-records"
],
"scripts": {
"start": "yarn serve",
"build": "tsc",
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
"prepare": "yarn build",
"prepublishOnly": "yarn test && yarn lint",
"preversion": "yarn lint",
"version": "yarn format && git add -A src",
"postversion": "git push && git push --tags",
"watch-node": "nodemon dist/index.js",
"test": "jest --verbose",
"watch-test": "yarn test -- --watchAll",
"watch-ts": "tsc -w",
"lint": "tsc --noEmit && eslint \"**/*.{js,ts}\" --quiet --fix",
"debug": "yarn build && yarn watch-debug",
"run-debug": "nodemon --inspect dist/server.js"
},
"dependencies": {
"@types/disposable-email-domains": "^1.0.1",
"axios": "^0.24.0",
"disposable-email-domains": "^1.0.59",
"mailcheck": "^1.1.1"
},
"devDependencies": {
"@types/eslint": "^6.1.1",
"@types/jest": "^24.0.23",
"@types/lodash": "^4.14.141",
"@types/mailcheck": "^1.1.31",
"@types/node": "^12.7.8",
"@typescript-eslint/eslint-plugin": "^2.3.1",
"@typescript-eslint/parser": "^2.3.1",
"eslint": "^6.4.0",
"jest": "^25.1.0",
"lodash": "^4.17.21",
"nodemon": "^2.0.15",
"ts-jest": "^25.2.1",
"ts-node": "^10.4.0",
"typescript": "^3.8.3"
}
}