├── .gitignore ├── test └── evalid │ └── core_test.clj ├── README.md ├── project.clj ├── resources └── logback.xml └── src └── evalid └── core.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | /logs 5 | /out.edn 6 | pom.xml 7 | pom.xml.asc 8 | *.jar 9 | *.class 10 | /.lein-* 11 | /.nrepl-port 12 | -------------------------------------------------------------------------------- /test/evalid/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns evalid.core-test 2 | (:require [clojure.test :refer :all] 3 | [evalid.core :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # evalid 2 | 3 | A Clojure library designed to ... well, that part is up to you. 4 | 5 | ## Usage 6 | 7 | FIXME 8 | 9 | ## License 10 | 11 | Copyright © 2014 FIXME 12 | 13 | Distributed under the Eclipse Public License either version 1.0 or (at 14 | your option) any later version. 15 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject evalid "0.1.0-SNAPSHOT" 2 | :description "Validate mailbox using SMTP" 3 | :dependencies [[org.clojure/clojure "1.7.0-alpha2"] 4 | [nettyca "0.1.0-SNAPSHOT"] 5 | [ch.qos.logback/logback-classic "1.1.2"]] 6 | :main evalid.core 7 | :aot [evalid.core]) 8 | -------------------------------------------------------------------------------- /resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %date %6level [%32thread] %-15logger{15} %msg%n 6 | 7 | 8 | 9 | 10 | logs/evalid.log 11 | 12 | logs/old/evalid.%d{yyyy-MM-dd}.log 13 | 3 14 | 15 | 16 | %date %6level [%32thread] %-15logger{15} %msg%n 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/evalid/core.clj: -------------------------------------------------------------------------------- 1 | (ns evalid.core 2 | (:require [nettyca.core :as nc] 3 | [clojure.tools.logging :as log] 4 | [clojure.core.async :refer [chan timeout go go-loop alts! 5 | ! close!] :as async]) 6 | (:gen-class)) 7 | 8 | (defmacro lwrite [c s n] 9 | `(do (log/info "smtp: writ:" ~s) 10 | (let [[v# c#] (alts! [[~c (str ~s "\r\n")] (timeout ~n)])] 11 | (identical? c# ~c)))) 12 | 13 | (defmacro lread [c n] 14 | `(let [[v# c#] (alts! [~c (timeout ~n)])] 15 | (log/info "smtp: read:" v#) 16 | v#)) 17 | 18 | (defn rvalid? [s] (and s (.startsWith s "2"))) 19 | 20 | (defn smtp-client [rcpt domain] 21 | (fn [r w c] 22 | (go (let [r0 (lread r 5000) 23 | w0 (when (rvalid? r0) 24 | (lwrite w (format "helo %s" domain) 5000)) 25 | r1 (when w0 (lread r 5000)) 26 | w1 (when (rvalid? r1) 27 | (lwrite w "mail from: " 5000)) 28 | r2 (when w1 (lread r 5000)) 29 | w2 (when (rvalid? r2) 30 | (lwrite w (format "rcpt to: <%s>" rcpt) 5000)) 31 | r3 (when w2 (lread r 15000)) 32 | rz (first (drop-while nil? [r3 r2 r1 r0]))] 33 | (log/info "smtp: done:" rcpt "->" rz) 34 | (close! r) (close! w) (close! c))))) 35 | 36 | (defn btake [c] 37 | (let [[nc v] (async/alts!! [c (timeout 10000)])] 38 | (identical? c nc))) 39 | 40 | (defn verify [{:keys [e m]} domain] 41 | (log/info "contacting mx:" m ", for email:" e) 42 | (nc/start m 25 (smtp-client e domain) :client)) 43 | 44 | (def verify-and-wait 45 | (comp btake :go-chan verify)) 46 | 47 | ;; out.edn is list of maps like: {:m mx-server :e email} 48 | 49 | (defn grab [] 50 | (read-string (slurp "out.edn"))) 51 | 52 | (defn -main [& args] 53 | (let [xs (grab)] 54 | (log/info "working on records:" (count xs)) 55 | (doseq [x xs] 56 | (when (:m x) 57 | (verify-and-wait x (first args)))))) 58 | 59 | (comment 60 | 61 | (def gs (grab)) 62 | (last gs) 63 | 64 | (verify (last gs) "bar.com") 65 | (verify-and-wait (last gs) "bar.com") 66 | 67 | ) 68 | --------------------------------------------------------------------------------