пятница, 7 ноября 2014 г.

clojure: how to send mail with attachment

It is pretty simple. This code can be used to send email via smtp. Attachment filename may be in unicode.


(defproject com.middlesphere/mailer "0.1"
  :description "simple mailer"
  :url "http://www.middlesphere.com"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [com.draines/postal "1.11.2"]
                 [com.sun.mail/javax.mail "1.5.2"]]
  :main ^:skip-aot mailer.core
  :target-path "target/%s"
  :omit-source true
  :profiles {:uberjar {:aot :all}})


(ns mailer.core
  (:require [clojure.edn :as edn])
  (:use [postal.core])
  (:import (javax.mail.internet MimeUtility)))

(defn show-help-exit
  (println "Usage: java -jar mailer.jar \"config-file\" \"email@email\" \"subject\" \"filename-with-body\" \"filename-with-attach\"\n ")
  (System/exit 0))

(defn -main
  "entry point to program."
  [& args]
  (println "start" (-> (java.text.SimpleDateFormat. "YYYY-mm-dd HH:mm:ss")
                       (.format (java.util.Date.))))

  (when (= "-h" (nth args 0))
  (when (not= 5 (count args))
    (println "error: wrong number of arguments!")

    (let [[config-file email-to subject body-file attach-file] args
          config (edn/read-string (slurp config-file))
          server-cfg {:host (config :host)
                      :port (config :port)}
          server-cfg (if (config :need-auth?)
                       (assoc server-cfg :user (config :user) :pass (config :pass))
          server-cfg (if (config :use-ssl?)
                       (assoc server-cfg :ssl true)
          server-cfg (if (config :use-tls?)
                       (assoc server-cfg :tls true)
      (println (format "config in:%s\nemail: %s\nsubject: %s\nbody in: %s\nattach in: %s\n" config-file email-to subject body-file attach-file))
      (println (send-message server-cfg                            
                             {:from (config :from)
                              :to email-to
                              :subject subject
                              :body [:alternative
                                     {:type (config :body-type)
                                      :content (slurp body-file)}
                                     {:type :attachment
                                      :content (java.io.File. attach-file)
                                      :file-name (MimeUtility/encodeText attach-file)
                                      :content-type (config :content-type)}]})))
    (catch Exception e (str "caught exception: " (.getMessage e))))
  (println "\nend" (-> (java.text.SimpleDateFormat. "YYYY-mm-dd HH:mm:ss")
                       (.format (java.util.Date.)))))


{:from "from@gmail.com"
 :host "smtp.gmail.com"
 :port 465
 :use-ssl? true
 :use-tls? false

 :need-auth? true
 :user "MyLogin"
 :pass "dis is passwd"

 :body-type "text/plain; charset=utf-8"
 :content-type "application/octet-stream"}

Test run

java -jar mailer-0.1-standalone.jar mailer-config.edn "to@gmail.com" "test-subject" "file-with-body.txt" "file-to-be-attached.doc"