├── .gitignore ├── AUTHORS.txt ├── .editorconfig ├── CHANGELOG.md ├── package.json ├── LICENSE ├── src └── args.js ├── bin └── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | # This list of authors is based on the git history of this repo. 2 | 3 | Ivakhnenko Dmitry 4 | Siarhei Bautrukevich 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.0.1 9 | 10 | The first public release. 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email-list-verify", 3 | "version": "0.0.1", 4 | "bin": { 5 | "email-list-verify": "./bin/index.js" 6 | }, 7 | "description": "CLI-tool to Verify a list of emails in a file.", 8 | "scripts": { 9 | "update-toc": "markdown-toc -i readme.md", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/uploadcare/email-list-verify.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/uploadcare/email-list-verify/issues" 18 | }, 19 | "keywords": [ 20 | "" 21 | ], 22 | "author": "Dmitry Ivakhnenko (https://github.com/jeetiss)", 23 | "license": "MIT", 24 | "dependencies": { 25 | "cli-spinners": "^1.3.1", 26 | "command-line-args": "^5.0.2", 27 | "command-line-usage": "^5.0.5", 28 | "email-deep-validator": "^3.1.0", 29 | "ora": "^3.0.0", 30 | "p-queue": "^3.0.0", 31 | "progress": "^2.0.3" 32 | }, 33 | "devDependencies": { 34 | "markdown-toc": "^1.2.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Uploadcare Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/args.js: -------------------------------------------------------------------------------- 1 | const usage = require("command-line-usage"); 2 | const commandLineArgs = require("command-line-args"); 3 | const package = require("../package.json"); 4 | 5 | const options = [ 6 | { 7 | name: "file", 8 | typeLabel: "{underline file}", 9 | description: "The input file with emails.", 10 | type: String, 11 | defaultOption: true 12 | }, 13 | { 14 | name: "output", 15 | typeLabel: "{underline file}", 16 | description: "The output file.", 17 | type: String, 18 | alias: "o", 19 | defaultValue: "result.csv" 20 | }, 21 | { 22 | name: "concurrency", 23 | typeLabel: "{underline number}", 24 | description: "Concurrency.", 25 | type: Number, 26 | alias: "c", 27 | defaultValue: 20 28 | }, 29 | { 30 | name: "help", 31 | description: "Print this usage guide.", 32 | alias: "h", 33 | type: Boolean 34 | } 35 | ]; 36 | 37 | const sections = [ 38 | { 39 | header: "Email-verificator", 40 | content: package.description 41 | }, 42 | { 43 | header: "Options", 44 | optionList: options 45 | }, 46 | { 47 | header: "Usage", 48 | content: [ 49 | "$ email-verificator {bold -o} {underline mails.csv} {underline mails-to-test.csv}", 50 | "$ email-verificator {bold -c} {underline 50} {underline mails.csv}", 51 | "$ email-verificator {bold --help}" 52 | ] 53 | } 54 | ]; 55 | 56 | const help = usage(sections); 57 | 58 | module.exports = { 59 | usage: () => console.log(help), 60 | arg: () => commandLineArgs(options) 61 | }; 62 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const EmailValidator = require("email-deep-validator"); 4 | const fs = require("fs"); 5 | const { promisify } = require("util"); 6 | const readline = require("readline"); 7 | const Queue = require("p-queue"); 8 | const cliSpinners = require("cli-spinners"); 9 | const ora = require("ora"); 10 | const { usage, arg } = require("../src/args"); 11 | 12 | const emailValidator = new EmailValidator(); 13 | const verify = emailValidator.verify.bind(emailValidator); 14 | 15 | const pickRandomValue = obj => { 16 | const values = Object.values(obj); 17 | return values[Math.floor(Math.random() * values.length)]; 18 | }; 19 | 20 | const spinner = ora({ 21 | text: "starting...", 22 | spinner: pickRandomValue(cliSpinners) 23 | }); 24 | let firstLine = true; 25 | 26 | try { 27 | const args = arg(); 28 | const inputFile = args.file; 29 | const outputFile = args.output; 30 | 31 | if (args.help || !inputFile) { 32 | return usage(); 33 | } 34 | 35 | spinner.start(); 36 | 37 | const output = fs.createWriteStream(outputFile); 38 | const input = readline.createInterface({ 39 | input: fs.createReadStream(inputFile) 40 | }); 41 | 42 | const queue = new Queue({ concurrency: args.concurrency }); 43 | 44 | const extractResult = email => info => ({ 45 | result: info.wellFormed && info.validDomain && info.validMailbox, 46 | info: 47 | info.wellFormed && info.validDomain && info.validMailbox 48 | ? `${email} is a valid address` 49 | : `${email} is an invalid address` 50 | }); 51 | 52 | input.on("line", line => { 53 | queue.add(() => 54 | verify(line) 55 | .then(extractResult(line)) 56 | .catch(error => ({ result: false, info: error.message })) 57 | .then(({ result, info }) => { 58 | spinner.text = info; 59 | output.write(`${line}, ${result}\n`); 60 | }) 61 | ); 62 | 63 | if (firstLine) { 64 | firstLine = false; 65 | 66 | queue.onIdle().then(() => { 67 | spinner.stopAndPersist({ 68 | symbol: "✅", 69 | text: `results in ${outputFile}` 70 | }); 71 | }); 72 | } 73 | }); 74 | 75 | input.on("error", error => { 76 | console.log(error.message); 77 | }); 78 | } catch (err) { 79 | console.log(err.message); 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Email-list-verify 2 | 3 | 4 | 7 | 8 | 9 | CLI-tool to Verify a list of emails in a file. `email-list-verify` is fast, 10 | lightweight, and helps validate emails stored in a plain text file where each 11 | email sits on a separate line (a single-column CSV does the trick too). 12 | 13 | The validation accuracy is similar to that of the free services you can find 14 | in organic search results. We tested the accuracy on the sample of 1000 emails. 15 | 16 | The output CSV file will have two unnamed columns holding emails and check 17 | results respectively. 18 | 19 | In the check results you will get the three possible values: 20 | 21 | * `true`, email is valid. 22 | * `false`, email is invalid. 23 | * `null`, email validation is disabled on a mail service provider, in many cases 24 | that can be considered `true`. 25 | 26 | The `email-list-verify` script is multi-threaded and allows controlling its 27 | concurrency via the `-c` option, see [CLI Usage](#cli-usage). 28 | 29 | 30 | 31 | * [Requirements](#requirements) 32 | * [Install](#install) 33 | * [CLI Usage](#cli-usage) 34 | * [Security issues](#security-issues) 35 | * [Feedback](#feedback) 36 | * [Authors](#authors) 37 | * [License](#license) 38 | 39 | 40 | 41 | 42 | 43 | ## Requirements 44 | 45 | You will need NodeJS and npm to run `email-list-verify`, 46 | 47 | * [Get NodeJs][ext-nodejs-get] 48 | * [Get npm][ext-npm-get] 49 | 50 | ## Install 51 | 52 | ```bash 53 | npm i -g email-list-verify 54 | ``` 55 | 56 | or 57 | 58 | ```bash 59 | yarn add global email-list-verify 60 | ``` 61 | 62 | ## CLI Usage 63 | 64 | ```bash 65 | Usage 66 | 67 | $ email-list-verify -o mails.csv mails-to-test.csv 68 | $ email-list-verify -c 50 mails.csv 69 | $ email-list-verify --help 70 | 71 | Options 72 | 73 | --file, file The input file with emails. 74 | -o, --output file The output file. 75 | -c, --concurrency number Concurrency. 76 | -h, --help Print this usage guide. 77 | ``` 78 | 79 | While most of the options are straightforward, `-c` could use additional 80 | explanation: it controls the number of threads for executing 81 | `email-list-verify` and defaults to `20`. Depending on the speed of your 82 | internet connection, you can set it to lower (slower) or higher values (faster). 83 | 84 | ## Security issues 85 | 86 | If you think you ran into something in Uploadcare libraries which might have 87 | security implications, please hit us up at 88 | [bugbounty@uploadcare.com][uc-email-bounty] or Hackerone. 89 | 90 | We'll contact you personally in a short time to fix an issue through co-op and 91 | prior to any public disclosure. 92 | 93 | ## Feedback 94 | 95 | Issues and PRs are welcome. You can provide your feedback or drop us a support 96 | request at [hello@uploadcare.com][uc-email-hello]. 97 | 98 | ## Authors 99 | 100 | * [Elijah][dayton-link], Idea, Readme 101 | * [Dmitry Ivakhnenko][jeetiss-link], Code 102 | * [Siarhei Bautrukevich][bautrukevich-link], Review 103 | 104 | ## License 105 | 106 | Released under the [MIT License](LICENSE). 107 | 108 | [ext-nodejs-get]: https://nodejs.org/en/download/ 109 | [ext-npm-get]: https://www.npmjs.com/get-npm 110 | [badge-stack-img]: https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat 111 | [badge-stack-url]: https://stackshare.io/uploadcare/stacks/ 112 | [uc-email-bounty]: mailto:bugbounty@uploadcare.com 113 | [uc-email-hello]: mailto:hello@uploadcare.com 114 | [jeetiss-link]: https://github.com/jeetiss 115 | [dayton-link]: https://github.com/dayton1987 116 | [bautrukevich-link]: https://github.com/bautrukevich 117 | --------------------------------------------------------------------------------