├── .gitignore ├── README.md ├── src ├── user.clj └── mailgun_dummy │ ├── server.clj │ ├── main.clj │ ├── sender.clj │ └── core.clj └── project.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mailgun-dummy 2 | 3 | A mock of Mailgun's email service. 4 | 5 | ## Usage 6 | 7 | You need leiningen installed. 8 | 9 | To start a web server for the application, run: 10 | 11 | lein run 12 | -------------------------------------------------------------------------------- /src/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | (:require [clojure.tools.namespace.repl :as repl] 3 | [mailgun-dummy.server :as server] 4 | [mount.core :as mount])) 5 | 6 | (defn start [] 7 | (mount/start)) 8 | 9 | (defn stop [] 10 | (mount/stop)) 11 | 12 | (defn reset [] 13 | (stop) 14 | (repl/refresh :after 'user/start)) 15 | -------------------------------------------------------------------------------- /src/mailgun_dummy/server.clj: -------------------------------------------------------------------------------- 1 | (ns mailgun-dummy.server 2 | (:require [mailgun-dummy.core :refer [handler]] 3 | [mount.core :refer [defstate]] 4 | [ring.adapter.jetty :as jetty])) 5 | 6 | (defn start [] 7 | (jetty/run-jetty #'handler {:port 5151 :join? false})) 8 | 9 | (defstate server 10 | :start (start) 11 | :stop (.stop server)) 12 | 13 | -------------------------------------------------------------------------------- /src/mailgun_dummy/main.clj: -------------------------------------------------------------------------------- 1 | (ns mailgun-dummy.main 2 | (:gen-class) 3 | (:require [mailgun-dummy.server] 4 | [mount.core :as mount])) 5 | 6 | (defn -main [] 7 | (mount/start)) 8 | 9 | (Thread/setDefaultUncaughtExceptionHandler 10 | (reify Thread$UncaughtExceptionHandler 11 | (uncaughtException [_ thread ex] 12 | (println "Uncaught exception on" (.getName thread)) 13 | (.printStackTrace ex)))) 14 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject mailgun-dummy "0.1.0-SNAPSHOT" 2 | :description "A mock of Mailgun's email service." 3 | :dependencies [[org.clojure/clojure "1.10.3"] 4 | [ring "1.9.4"] 5 | [compojure "1.6.2"] 6 | [org.clojure/data.xml "0.0.8"] 7 | [org.clojure/data.zip "1.0.0"] 8 | [mount "0.1.16"] 9 | [org.clojure/tools.namespace "1.1.0"] 10 | [org.clojure/core.async "1.4.627"] 11 | [clj-time "0.15.2"] 12 | [clj-http "3.12.3"] 13 | [cheshire "5.10.1"]] 14 | :main mailgun-dummy.main) 15 | -------------------------------------------------------------------------------- /src/mailgun_dummy/sender.clj: -------------------------------------------------------------------------------- 1 | (ns mailgun-dummy.sender 2 | (:require [clj-http.client :as http] 3 | [clojure.core.async :refer [")) 19 | 20 | (defn valid-email? [s] 21 | (or (re-find #"^[^@<>]+@[^@<>]+\.[^@<>]+$" s) 22 | (re-find #"^[^<]+ <[^@<>]+@[^@<>]+\.[^@<>]+>$" s))) 23 | 24 | (defn valid-message? [{:keys [from to subject text html]}] 25 | (and (string? from) (valid-email? from) 26 | (string? to) (valid-email? to) 27 | (string? subject) 28 | (or (string? text) 29 | (string? html)))) 30 | 31 | (defn send-email [message] 32 | (let [message (walk/keywordize-keys message) 33 | message (assoc message :id (generate-id message))] 34 | (if (valid-message? message) 35 | (do 36 | (println "Received message" (pr-str (dissoc message :id))) 37 | (put! sender message) 38 | (create-response message)) 39 | (do 40 | (println "Recevied invalid message" (pr-str (dissoc message :id))) 41 | {:status 400 :body "Invalid message!"})))) 42 | 43 | (def handler 44 | (-> (fn [req] 45 | (if (= (get-in req [:headers "authorization"]) 46 | "Basic YXBpOm1haWxndW4tZHVtbXkta2V5") ;; :basic-auth ["api" "mailgun-dummy-key"] 47 | (send-email (:params req)) 48 | (do 49 | (println "Unauthorized request, set :mailgun-api-key to \"mailgun-dummy-key\"") 50 | {:status 401 :body "Unauthorized"}))) 51 | (ring.middleware.multipart-params/wrap-multipart-params) 52 | (ring.middleware.params/wrap-params))) 53 | --------------------------------------------------------------------------------