Code Monkey home page Code Monkey logo

postal's Introduction

CircleCI

postal

Internet email library for Clojure

postal is a library for constructing and sending RFC822-compliant Internet email messages. It wraps the Jakarta Mail package for message and SMTP support. It supports sendmail natively. Supports STARTTLS & SSL.

Platforms

  • Anything that can run Java should work
  • sendmail support likely requires *nix, but msmtp, et al., are worthy substitutes
  • Untested on Windows

Dependencies

  • Jakarta Mail (in lib/ after build)
  • Java 8+

Install

Served by Clojars. In your Leiningen project.clj:

Clojars Project

Likewise substitute any tag name from git.

Examples

Local

At a bare minimum, provide a map with :from and :to (and you'll probably also be wanting :subject and :body, though they're technically optional). Any other keys you supply will show up as ancillary headers. This example will locally inject the message into whatever sendmail-compatible interface your system provides.

user> (in-ns 'postal.core)
#<Namespace postal.core>
postal.core> (send-message {:from "[email protected]"
                            :to ["[email protected]" "[email protected]"]
                            :cc "[email protected]"
                            :subject "Hi!"
                            :body "Test."
                            :X-Tra "Something else"})
{:code 0, :error :SUCCESS, :message "message sent"}
postal.core>

SMTP

To use SMTP, add an argument map before the message with at least :host key.

postal.core> (send-message {:host "mail.isp.net"}
                           {:from "[email protected]"
                            :to "[email protected]"
                            :subject "Hi!"
                            :body "Test."})
{:code 0, :error :SUCCESS, :message "message sent"}
postal.core>

For legacy compatibility, you can also supply these connection parameters as metadata on the message. (send-message ^{:host ...} {:from ...})

Authentication

Authenticate to SMTP server with :user and :pass.

postal.core> (send-message {:host "mail.isp.net"
                            :user "jsmith"
                            :pass "sekrat!!1"}
                           {:from "[email protected]"
                            :to "[email protected]"
                            :subject "Hi!"
                            :body "Test."})
{:code 0, :error :SUCCESS, :message "message sent"}
postal.core>

Encryption (Gmail example)

You probably do not want to do this in the clear, so add :ssl to get an encrypted connection. This will default to port 465 if you don't specify one.

If your destination supports TLS instead, you can use :tls. This will default to port 25, however, so if you need a different one make sure you supply :port. (It's common for ISPs to block outgoing port 25 to relays that aren't theirs.)

postal.core> (send-message {:host "smtp.gmail.com"
                            :user "[email protected]"
                            :pass "sekrat!!1"
                            :port 587
                            :tls true}
                           {:from "[email protected]"
                            :to "[email protected]"
                            :subject "Hi!"
                            :body "Test."})
{:code 0, :error :SUCCESS, :message "message sent"}
postal.core>

(Despite the documentation mentioning SSL, your Google account is most likely restricted to TLS on port 587 and furthermore you may have to configure your account to "allow less secure apps" in order to send emails.)

Amazon

Since Amazon SES uses authenticated SMTP, postal can use it. Just make sure you use a verified address and your SMTP credentials (visit the AWS Console to set those up). Also, if you're just sandboxing, you can only send to a verified address as well. Example:

postal.core> (send-message {:user "AKIAIDTP........" :pass "AikCFhx1P......."
                            :host "email-smtp.us-east-1.amazonaws.com"
                            :port 587}
               {:from "[email protected]" :to "[email protected]"
                :subject "Test from Amazon SES" :body "Test!!!11"})
{:error :SUCCESS, :code 0, :message "messages sent"}
postal.core>

Attachments

Attachments and multipart messages can be added as sequences of maps:

postal.core> (send-message {:host "mail.isp.net"}
                           {:from "[email protected]"
                            :to "[email protected]"
                            :subject "Hi!"
                            :body [{:type "text/html"
                                    :content "<b>Test!</b>"}
                                   ;;;; supports both dispositions:
                                   {:type :attachment
                                    :content (java.io.File. "/tmp/foo.txt")}
                                   {:type :inline
                                    :content (java.io.File. "/tmp/a.pdf")
                                    :content-type "application/pdf"}]})
{:code 0, :error :SUCCESS, :message "message sent"}
postal.core>

If your attachment has a content-type that is not recognized by Jakarta Mail, e.g., .pdf or .doc, you can set :content-type. You can also set :file-name and :description if you don't like the filename that :content uses.

If you want another multipart type than "mixed", you can specify it as a keyword as the first value in the map sequence. That way you can for example create an HTML-Email that displays a text message as fallback in email clients that do not support (or suppress) HTML-mails:

postal.core> (send-message {:host "localhost"
                            :port 2500
                            :user "user@localhost"
                            :pass "somePassword"}
                       {:from "[email protected]"
                        :to "[email protected]"
                        :subject "multipart/alternative test"
                        :body [:alternative
                               {:type "text/plain"
                                :content "This is a test."}
                               {:type "text/html"
                                :content "<html><head> </head><body>
                                <h1>Heading 1</h1><p>This is a test.</p>
                                </body></html>"}
                              ]}))

UTF-8

Postal uses Jakarta Mail underneath, which defaults to charset us-ascii. To set the charset, set the :type, like "text/html; charset=utf-8".

Message ID

Postal will supply a message ID by default that looks like [random]@postal.[host]. You can customize this by supplying a :message-id header with a function that takes no args. The included postal.support/message-id can be used if you'd like to make use of its randomness and only customize the hostname.

{:from "[email protected]"
 :to "[email protected]"
 :subject "Message IDs!"
 :body "Regards."
 :message-id #(postal.support/message-id "foo.bar.dom")}

User Agent

You can customize the default User-Agent header (by default postal/VERSION).

{:from "[email protected]"
 :to "[email protected]"
 :subject "Message IDs!"
 :body "Regards."
 :user-agent "MyMailer 1.0"}

Stress-testing

You can stress-test a server by:

postal.core> (stress ^{:host "localhost"
                       :num     1000
                       :delay   250   ;; msecs
                       :threads 5     ;; concurrent connections}
                     {:from "[email protected]"
                      :to "[email protected]"})
sent 1000 msgs to localhost:25
nil
postal.core>

Building

% lein deps && lein jar

Contributors

Alexander Kouznetsov
Allen Rohner
Andre Branco
Andres Cuervo
Andy Fingerhut
Camille Troillard
Christoph Henkelmann
Colin Jones
Dante Briones
Dimas Guardado
Gerrit Hentschel
J. David Lowe
Jeff Palmucci
Joe Gallo
Kevin DeJong
Kyle Kingsbury
Paul Biggar
Paul Stadig
Phil Hagelberg
Peter Onneby
Roman Flammer
Sam Ritchie
Stephen Nelson

License

Postal is (c) 2009-2019 Andrew A. Raines and released under the MIT license.

postal's People

Contributors

aphyr avatar arohner avatar avbranco avatar bo-chen avatar charles-dyfis-net avatar chenkelmann avatar cwervo avatar dbriones avatar dguardado avatar dlowe avatar drewr avatar gerrit-hntschl avatar jafingerhut avatar joegallo avatar modax avatar mrkam2 avatar pawelstroinski avatar pbiggar avatar pjstadig avatar poenneby avatar ryfow avatar slava92 avatar sritchie avatar sumbach avatar technomancy avatar trptcolin avatar tuscland avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

postal's Issues

UnknowHostException

Hey!

I end up having a really odd problem here when I try to send mail.
This "used" to work, but since I reinstalled my computer it stopped... any help would be very appreciated.

user=> gmail
{:ssl true, :host "smtp.gmail.com", :user "[email protected]", :pass "my_password"}

user=> (send-message gmail { :from "[email protected]" :to "[email protected]" :subject "FOO" :body "bar"} )

UnknownHostException marvin: nodename nor servname provided, or not known  java.net.Inet6AddressImpl.lookupAllHostAddr (Inet6AddressImpl.java:-2)

I did some research and found a couple of places in the code base where Inet6Addresses are being used, but can't really understand why my hostname should be affecting mail sending :/

com.sun.mail.smtp.SMTPSendFailedException: 451 Auth Fail

I got this following error.

com.sun.mail.smtp.SMTPSendFailedException: 451 Auth Fail. Check this URL: http://cs.daum.net/faq/43/9234.html?page=5#33119

com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:1388)
com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1215)
com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:586)
postal.smtp$smtp_send_STAR_.invoke(smtp.clj:36)
postal.smtp$smtp_send.doInvoke(smtp.clj:58)
clojure.lang.RestFn.invoke(RestFn.java:423)
postal.core$send_message.invoke(core.clj:35)
toeic_score.routes.user$mailto$fn__654.invoke(user.clj:315)
liberator.core$run_handler.invoke(core.clj:178)
liberator.core$handle_created.invoke(core.clj:233)
liberator.core$decide.invoke(core.clj:85)
liberator.core$new_QMARK_.invoke(core.clj:235)
liberator.core$decide.invoke(core.clj:85)
liberator.core$post_redirect_QMARK_.invoke(core.clj:237)
liberator.core$decide.invoke(core.clj:85)
liberator.core$post_BANG_.invoke(core.clj:243)
liberator.core$decide.invoke(core.clj:85)

and this is my code:

(send-message {:host "smtp.daum.net"
:port 465
:user "userid"
:pass "password"
:ssl :yes}
{:from "[email protected]"
:to "[email protected]"
:subject "test"
:body "hello"})

It works fine on local. but i deployed this on AWS. it doesn't work for me.

plz help.

Use something else than :error keyword in the result map to indicate success

Logically, {:error :SUCCESS} seems a bit confusing. If a method returns a result map, one would expect that e.g. if (contains? r :error) resolves to true it would be indicative of an error. Similarly, (:error result) is always true here, even if everything worked out well. This seems a bit counter-intuitive.
Imho, {:error :SUCCESS} is an oxymoron, so I would argue to use something more self-explanatory, e.g. :result :SUCCESS should be used - I would expect :error keyword to be present in a map and to have a non-nil value only in case of an error.

Requesting change log for v2?

Hi Drew,

I notice that the CHANGES file hasn't been updated for [com.draines/postal "2.0.0"] yet. Any chance we could request an update? Are there any breaking changes?

Thanks a lot! (And a big thanks for your great work on Postal).

Cheers :-)

Support Session reuse

Mark Derricutt writes, "Is there support in this lib currently for reusing an existing MailSession (or passing in say "java://comp/env/mail/Session" and having it handle the lookup?"

JDK 9+ compatibility: DataHandler missing

In JDK9+, DataHandler appears to be dropped. Therefore, an error is thrown:

#error {
 :cause javax.activation.DataHandler
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message Syntax error compiling at (postal/message.clj:1:1).
   :data #:clojure.error{:phase :compile-syntax-check, :line 1, :column 1, :source postal/message.clj}
   :at [clojure.lang.Compiler load Compiler.java 7648]}
  {:type java.lang.ClassNotFoundException
   :message javax.activation.DataHandler
   :at [java.net.URLClassLoader findClass URLClassLoader.java 436]}]}

To add a workaround, one can add this dependency to your project:

[com.sun.activation/javax.activation "1.2.0"]

Tested with AdoptOpenJDK 13

But this is just a workaround. Please update the corresponding lines in the code base.

Thanks!

Message format

I'm working on an IMAP wrapper that I'd like to integrate with Postal later on, but there are a few incompatibilities or inconsistencies.

For a multipart message, you suggest

{:from "[email protected]"
 :to "[email protected]"
 :subject "Hi!"
 :body [{:type "text/html"
     :content "<b>Test!</b>"}
     ;;;; supports both dispositions:
     {:type :attachment
     :content (java.io.File. "/tmp/foo.txt")}
     {:type :inline
     :content (java.io.File. "/tmp/foo.txt")}]}

This is almost equal to what I produce, except that you use both :content and :body, and :type for both :content-type and :content-disposition, why? Are they interchangeable, or is there a difference?

An example message of mine, which is a rather straightforward conversion:

{:subject "anther test",
 :from "Pepijn de Vos <[email protected]>",
 :date "Thu, 17 Nov 2011 17:28:50 +0100",
 :to "[email protected]",
 :content
 ({:content "Hi\r\n\r\n",
   :content-type "text/plain; charset=\"us-ascii\"",
   :mime-version "1.0",
   :content-transfer-encoding "7bit"}
  {:content
   ({:content
     "<html><head></head><body style=\"word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; \">Hi<div><br></div><div><img height=\"240\" width=\"240\" apple-width=\"yes\" apple-height=\"yes\" id=\"e5e7beb3-323d-4657-8018-bac9bf8fdfc2\" src=\"cid:02374C7B-D4AB-4D39-A892-8FC5B025A9EF@lan\"><img height=\"240\" width=\"240\" apple-width=\"yes\" apple-height=\"yes\" id=\"c87d9bc1-42ac-4c78-b8b8-efb050267160\" src=\"cid:E986AD1E-5A70-4301-89D1-0AB4BD62181E@lan\"></div></body></html>",
     :content-type "text/html; charset=\"us-ascii\"",
     :mime-version "1.0",
     :content-transfer-encoding "7bit"}
    {:content
     #<BufferedImage BufferedImage@64900079: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@2a0f3b83 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 240 height = 240 #numDataElements 4 dataOff[0] = 3>,
     :content-type "image/png; name=\"illusion.png\"",
     :mime-version "1.0",
     :content-id "<02374C7B-D4AB-4D39-A892-8FC5B025A9EF@lan>",
     :content-disposition "inline; filename=\"illusion.png\"",
     :content-transfer-encoding "base64"}
    {:content
     #<BufferedImage BufferedImage@4e0c2b07: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@2a0f3b83 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 240 height = 240 #numDataElements 4 dataOff[0] = 3>,
     :content-type "image/png; name=\"square.png\"",
     :mime-version "1.0",
     :content-id "<E986AD1E-5A70-4301-89D1-0AB4BD62181E@lan>",
     :content-disposition "inline; filename=\"square.png\"",
     :content-transfer-encoding "base64"}),
   :content-type
   "multipart/related;\r\n boundary=\"===============7617467129600379649==\"",
   :mime-version "1.0"}),
 :received
 "from ubuntu.lan (ip4da451b5.direct-adsl.nl. [77.164.81.181]) by\r\n mx.google.com with ESMTPS id f41sm91056321eec.5.2011.11.17.08.28.50\r\n (version=TLSv1/SSLv3 cipher=OTHER); Thu, 17 Nov 2011 08:28:53 -0800 (PST)",
 :content-type
 "multipart/alternative;\r\n boundary=\"===============4025336257788734124==\"",
 :mime-version "1.0",
 :dkim-signature
 "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;\r\n h=from:content-type:subject:date:message-id:to:mime-version:x-mailer;\r\n bh=aHrYvWBg8oYhUws6PWTTAvMs9wUsBG0OfADodtVoP40=;\r\n b=TH+x17rro680gVsA0e5numk5JiOJPnaYCNafeN4ubkJCG3r5y4Ttk2xw+cN35wqaop\r\n zeqO1RcRfVWXozquGNIWa6Xo7E/JPSvH62jnionnrnZU7qN2Vyr0SIFwZWcCFMR5Wxkd\r\n 0JqJLT4hbQ+W1HM+W5AGTGntYNDw7OfDG7emI=",
 :message-id "<[email protected]>",
 :x-mailer "Apple Mail (2.1251.1)"}

Correctly encode filenames

When attachments use filenames with unicode characters in them, sending could fail. A fix is to run a filename through javax.mail.internet.MimeUtility encodeText as following:

(fn [filename] (. javax.mail.internet.MimeUtility encodeText filename "UTF-8" nil))

Is it possible to incorporate this encoding?

NullPointerException when no file name in attachment

Dear Drew, I am using successfully your library for building an email and I found out today while creating

{:type :attachment
 :content-type (email-impl/guess-mime "http://lorempixel.com/400/200/" "image/jpeg")
 :content (io/as-url "http://lorempixel.com/400/200/")}

Throws a NPE:

java.lang.NullPointerException
    at javax.mail.internet.MimeUtility.quote(MimeUtility.java:927) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.ParameterList.quote(ParameterList.java:649) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.ParameterList.access$200(ParameterList.java:71) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.ParameterList$ToStringBuffer.addNV(ParameterList.java:617) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.ParameterList.toString(ParameterList.java:598) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.ContentDisposition.toString(ContentDisposition.java:185) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.MimeBodyPart.setFileName(MimeBodyPart.java:1161) ~[mailapi-1.4.3.jar:1.4.3]
    at javax.mail.internet.MimeBodyPart.setFileName(MimeBodyPart.java:531) ~[mailapi-1.4.3.jar:1.4.3]
    at postal.message$eval_bodypart.invokeStatic(message.clj:108) ~[?:?]
    at postal.message$eval_bodypart.invoke(message.clj:104) ~[?:?]
    at postal.message$eval54499$fn__54500.invoke(message.clj:98) ~[?:?]
    at postal.message$eval54482$fn__54483$G__54473__54488.invoke(message.clj:94) ~[?:?]
    at postal.message$eval_multipart.invokeStatic(message.clj:137) ~[?:?]
    at postal.message$eval_multipart.invoke(message.clj:127) ~[?:?]
    at postal.message$add_multipart_BANG_.invokeStatic(message.clj:141) ~[?:?]
    at postal.message$add_multipart_BANG_.invoke(message.clj:140) ~[?:?]
    at postal.message$add_body_BANG_.invokeStatic(message.clj:151) ~[?:?]
    at postal.message$add_body_BANG_.invoke(message.clj:148) ~[?:?]
    at postal.message$make_jmessage.invokeStatic(message.clj:177) ~[?:?]
    at postal.message$make_jmessage.invoke(message.clj:157) ~[?:?]
    at postal.message$make_jmessage.invokeStatic(message.clj:166) ~[?:?]
    at postal.message$make_jmessage.invoke(message.clj:157) ~[?:?]

I check the source and it fails here because re-find returns nil. Probably a simple dummy file name would avoid this issue right?

Thanks!

send-message in 1.11.4 results in StackOverflowError at java.io.UnixFileSystem.getBooleanAttributes0 (UnixFileSystem.java:-2)

Hello.
Trying to use Postal on my Ubuntu 14.04. Version 1.11.4 throws the Exception. Version 1.11.3 works fine.
REPL pieces.

1.11.4

app.util.mail=> (send-message {:from "[email protected]"
           #_=>                :to "[email protected]"
           #_=>                :subject "lol"
           #_=>                :body "<h1>KEKE</h1>"})

StackOverflowError   java.io.UnixFileSystem.getBooleanAttributes0 (UnixFileSystem.java:-2)
app.util.mail=> *e
#error {
 :cause nil
 :via
 [{:type java.lang.StackOverflowError
   :message nil
   :at [java.io.UnixFileSystem getBooleanAttributes0 "UnixFileSystem.java" -2]}]
 :trace
 [[java.io.UnixFileSystem getBooleanAttributes0 "UnixFileSystem.java" -2]
  [java.io.UnixFileSystem getBooleanAttributes "UnixFileSystem.java" 242]
  [java.io.File isFile "File.java" 882]
  [postal.sendmail$find_sendmail$fn__31529 invoke "sendmail.clj" 61]
  [clojure.core$filter$fn__4580 invoke "core.clj" 2686]
  [clojure.lang.LazySeq sval "LazySeq.java" 40]
  [clojure.lang.LazySeq seq "LazySeq.java" 49]
  [clojure.lang.LazySeq first "LazySeq.java" 71]
  [clojure.lang.RT first "RT.java" 653]
  [clojure.core$first__4110 invoke "core.clj" 55]
  [postal.sendmail$find_sendmail invoke "sendmail.clj" 61]
  [postal.sendmail$sendmail_send invoke "sendmail.clj" 68]
  ... 500+ identical lines ...
  [postal.sendmail$sendmail_send invoke "sendmail.clj" 68]]}

1.11.3

app.util.mail=> (send-message {:from "[email protected]"
           #_=>                :to "[email protected]"
           #_=>                :subject "lol"
           #_=>                :body "<h1>KEKE</h1>"})
{:code 0, :error :SUCCESS, :message "message sent"}
app.util.mail=>

My system:
OS: Ubuntu 14.04
Java: java version "1.8.0_60" (HotSpot)
Using postfix to send mail.

Workaround: currently I just switched back to 1.11.3, which works fine.

I can provide more info if needed.

IOFactory error when used in Uberjar

When postal is used in a uberjar, it fails trying to read the pom.properties file with this error:

java.lang.IllegalArgumentException: No implementation of method: :make-input-stream of protocol: #'clojure.java.io/IOFactory found for class: nil

Stack trace:
https://gist.github.com/kirillsalykin/011e5479d0f2b9c2a81d

WORKAROUND:
Add -Dpostal.version=1.11.3 to java process

Here is a reproducible example:
https://github.com/InspireNL/TeamHappiness

See stackoverflow for discussion:
http://stackoverflow.com/questions/32235680/sending-email-with-postal-from-heroku-fires-strange-exception/

Permission denied for send-message function

image
hi,
I am going to use smtp to send out email from my laptop, but as you can see the screenshot, I always got a “Permission denied” error. but once I use the python script with the same smtp credentials, it works...
Do you have any idea about this?

Thanks
Eyck

charset problem

When I put unicode characters in subject line and message body, for the first a few messages it worked good, but subsequence messages were delivered with wrong charset:

Content-Type: text/plain; charset=ANSI_X3.4-1968

all unicode characters are showing as question marks.

Expose Process.getErrorStream() content from postal.sendmail/sendmail-send

postal.sendmail/errors contains only a subset of errors that can happen.

Please expose Process.getErrorStream() content from postal.sendmail/sendmail-send, as this can seriously help in debugging exit values such as 1.

It may be enough to just replace:

(error (.exitValue p))

with:

(assoc (error (.exitValue p))
  :stderr (slurp (.getErrorStream p)))

SSL syntax from README.md

Hi in the README.md under Gmail authentication the example to use SSL uses this syntax

postal.core> (send-message {:host "smtp.gmail.com"
                            :user "jsmith"
                            :pass "sekrat!!1"
                            :ssl :yes!!!11}

But an example in #22 shows this syntax for using :ssl

(postal/send-message #^{:host "email-smtp.us-east-1.amazonaws.com"
                      :user (get (System/getenv) "AWS_SMTP_USER")
                      :pass (get (System/getenv) "AWS_SMTP_PASSWORD")
                      :ssl true }

What is the correct method for enabling :ssl?

setSubject is not setting charset

Norwegian characters (æøå) in the subject are shown as "?" in Gmail. When used in the body, they are shown okay. Sending to Gmail through SendGrid.

skjermbilde 2013-09-11 kl 16 29 39

                           {:from from
                            :to email
                            :subject "Test æøå"
                            :charset "utf-8"
                            :body [{:type "text/html; charset=utf-8"
                                    :content "Test æøå"}]}))))

I built a local version that adds charset to the setSubject call:

terjesb@00529b1

This fixes it for me. Not sure why all the other calls use charset and setSubject does not?

The existing tests still pass, but I haven't been able to make a test specifically for utf-8. Locally on OS X, the current tests seem to work with utf-8 as-is.

SMTP metadata problems

I have problems to configure Postal for smtp. It seems like the metadata is stripped of.

(postal/send-message #^{:host "email-smtp.us-east-1.amazonaws.com"
                      :user (get (System/getenv) "AWS_SMTP_USER")
                      :pass (get (System/getenv) "AWS_SMTP_PASSWORD")
                      :ssl true }
                   {:from '[email protected]' :to '[email protected]' :subject 'test' :body 'test'})

Ignores the smtp settings and uses sendmail instead..

How to get TLS for gmail to work??

I see in the README that STARTTLS and TLS is supposed to be supported. I read issue #7 and the old pull #11 that looked to solve this. But I cannot get gmail to accept this using any 'obvious' combination of parameters in the arguments map. In particular, using just :port 587 results in

SMTPSendFailedException 530 5.7.0 Must issue a STARTTLS command first.

Using :tls true results in same error as using :ssl true or both :ssl true and :port 587 result in 'less secure app' error => google thinks tls is not being used.

Looking at support.clj, it looks like there is some way to enable this as there are indications that starttls.enable can be activated, but the how of doing this is totally opaque to me.

Any suggestions / answers?

Thanks

embedding attached images in html not working.

I am sending an email with this body:

:body [
{:type "text/html;charset=utf-8;"
                :content "<div> <img src=\"cid:file.png\"> <div>"
                }
{:type :attachment
                :content (java.io.File. "/path/to/file.png")}
]

My goal is to have the attached file.png be loaded as an image in the html. However, even though the attachment is being sent, the file isn't being loaded in the html. How do I fix this?

memory leak

I'm pretty sure there's a memory leak in send-message, at least under some circumstances. I have narrowed it down to just running this loop:

(dotimes [n 2000]
(let [uuid1 (myutil/random-uuid)
uuid2 (myutil/random-uuid)
uuid3 (myutil/random-uuid)]
(println "sending TEST email subj " uuid1)
(try (let [fromname "my name blalablabla" ]
(postalemail/send-message mycred/conn-from-me
{
:from (str fromname " <" mycred/crm-email ">")
:to [email protected]
:subject uuid2
:body [ {:type "text/html" :content uuid3 }] })
true) ; success in sending e-mail
(catch Exception e (do (myutil/write-important-log
; failed sending e-mail
"TEST Send-Email exception: " (.getMessage e))
false ; failure in sending
)))
(Thread/sleep 10000)
))

When this loop is running, and a message is sent every 10sec, I can clearly see memory use rising (using top) from 8.3% to 9.1% over around 15 minutes. (sending around 50-100 e-mails).
If this code does not run, memory use doesn't rise.

If anyone has any idea on why that happens, and how to fix that, I'd be happy to hear.
I suppose some memory needs to be freed after sending the e-mail, but I don't really know the Java API and how to do that.

Thanks

Bump javax.mail/mail dep to 1.5.4

Would it be possible to bump the dependency on javax.mail/mail to version 1.5.4, please? For example, io.forward/clojure-mail is already using it.

Authentication error while using postal

Hi @drewr

I am trying to use this library to send messages via my gmail account to another gmail account.

Here's the sample code I've used from the ReadMe

(ns hello-from-devnagri.scratch-postal
  (:require [postal.core :refer [send-message]]))



  (def email "****")
  (def pass "****")

(def conn {:host "smtp.gmail.com"
           :ssl true
           :user email
           :pass pass})


(send-message conn
              {:from "[email protected]"
               :to "[email protected]"
               :subject "Hi!"
               :body "Test."})


But so far, I keep running into authentication error


1. Unhandled javax.mail.AuthenticationFailedException
   534-5.7.14
   <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbuy
   534-5.7.14
   K32hXN973NPcf2crjl84tlwHQaSpGoM7C4VgKiVtQ0m3085JxLUK_xYLahVL7foVHFaNLa
   534-5.7.14
   7RDOag04GA4PpaBfGQ6EjvRiZviX5E5aaTsPsW3yP3P76PquiKAbGacV4WKoeuc10x3RX2
   534-5.7.14
   o2b9YioEU1w0ZRz7KLpT0leRCYySaHdpwNoMW8Y9gDMEZnnkVsWSP_OXIDiCLCXHEjOzs1
   534-5.7.14 pDbu-G_N1ABEOfVgyOiaMG2HWzH0ZwY9CWJv1fryNN1EhRbLH-> Please log in
   via 534-5.7.14 your web browser and then try again. 534-5.7.14 Learn more at
   534 5.7.14 https://support.google.com/mail/answer/78754 v5sm74349272pgn.5 -
   gsmtp


        SMTPTransport.java:  914  com.sun.mail.smtp.SMTPTransport$Authenticator/authenticate
        SMTPTransport.java:  825  com.sun.mail.smtp.SMTPTransport/authenticate
        SMTPTransport.java:  730  com.sun.mail.smtp.SMTPTransport/protocolConnect
              Service.java:  366  javax.mail.Service/connect
                  smtp.clj:   33  postal.smtp/smtp-send*
                  smtp.clj:   29  postal.smtp/smtp-send*
                  smtp.clj:   58  postal.smtp/smtp-send
                  smtp.clj:   39  postal.smtp/smtp-send
               RestFn.java:  423  clojure.lang.RestFn/invoke
                  core.clj:   35  postal.core/send-message
                  core.clj:   29  postal.core/send-message
                      REPL:   15  hello-from-devnagri.scratch-postal/eval17031
                      REPL:   15  hello-from-devnagri.scratch-postal/eval17031
             Compiler.java: 7062  clojure.lang.Compiler/eval
             Compiler.java: 7025  clojure.lang.Compiler/eval
                  core.clj: 3206  clojure.core/eval
                  core.clj: 3202  clojure.core/eval
                  main.clj:  243  clojure.main/repl/read-eval-print/fn
                  main.clj:  243  clojure.main/repl/read-eval-print
                  main.clj:  261  clojure.main/repl/fn
                  main.clj:  261  clojure.main/repl
                  main.clj:  177  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  657  clojure.core/apply
                  core.clj:  652  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  657  clojure.core/apply
                  core.clj: 1965  clojure.core/with-bindings*
                  core.clj: 1965  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
    interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
                  AFn.java:   22  clojure.lang.AFn/run
   ThreadPoolExecutor.java: 1149  java.util.concurrent.ThreadPoolExecutor/runWorker
   ThreadPoolExecutor.java:  624  java.util.concurrent.ThreadPoolExecutor$Worker/run
               Thread.java:  748  java.lang.Thread/run



Could you kindly please help me out here ?

string as attachment

I need to create an attachment and it seems the only way is actually to create a file on disk. I already have the content as a string, can postal make attachmenet from information in memory?

Is the attached file left open?

I used this code and after finish I can´t delete the attached file, any idea?
(send-message {:host "smtp.gmail.com" :user usuario :pass senha :tls :yes :port 587} {:from usuario :to destino :subject "Reports" :body [{:type "text/html" :content (clojure.string/replace (slurp template) #"\$mes" mes)} {:type :inline :content (java.io.File. anexo) :content-type "application/pdf"}]})

Using ByteArrayDataSource for attachments, possible?

I have several dynamically created PDFs that I want to attach to an email, is it possible to attach them via stream wizardry rather than writing the to a file first?

I dug through the code but it looks like attachments are always assumed to be files or coercible to files.

Thanks.

release 0.1.7 or update snapshot

Would you be able to release a new version or even a new snapshot? We're using 0.1.7-SNAPSHOT and got hit by issue #15, which looks like it was fixed 3 months ago. Thanks!

Support passing settings as an argument, not metadata

Some functions do not preserve metadata which is lost silently. It is incredibly confusing to beginners.

The decision to use metadata for stuff as important as connection parameters was a mistake. Please get rid of it and use a regular argument.

Unable to send multiple headers with same key, but different value

I'm trying to set multiple tags in mailgun using the X-Mailgun-Tag header, and it expects each tag to be sent in a different header.

Since maps only allow one value per key, it would be nice to maybe support seqs as values in the message map for extra headers, e.g.:

{ "X-Mailgun-Tag" ["foo" "bar"] }

Ideally this would add a header for each value in the seq.

Reflection warnings

Reflection warning, postal/message.clj:51:28 - reference to field getAddress can't be resolved.
Reflection warning, postal/message.clj:52:28 - reference to field getPersonal can't be resolved.
Reflection warning, postal/message.clj:139:5 - call to method setText on javax.mail.Message can't be resolved (no such method).
Reflection warning, postal/message.clj:161:17 - call to postal.message.proxy$javax.mail.internet.MimeMessage$ff19274a ctor can't be resolved.
Reflection warning, postal/message.clj:163:21 - call to method setHeader can't be resolved (target class is unknown).
Reflection warning, postal/sendmail.clj:74:16 - call to java.lang.ProcessBuilder ctor can't be resolved.

[PATCH] Support attachments from URLs

Hello,

currently, it is only possible to add attachments from the file. However, sometimes it could be useful to attach files from classpath resources which might be within JAR files.

The patch below adds support for this.

From f11da6cd47fd9ce28cca3278f908f094499741bd Mon Sep 17 00:00:00 2001
From: Modestas Vainius <[email protected]>
Date: Sun, 1 Dec 2013 20:51:54 +0200
Subject: [PATCH] Support attachments from URLs.

This commit adds support for adding attachments from URLs. Up until now
only files (and file: URLs) were supported. Paths without protocol
string are still assumed to be files on the local file system as before.

This is mainly for adding attachments from resources which might be
within JAR files (as returned by clojure.java.io/resource).

---
 src/postal/message.clj       | 15 ++++++++++++---
 test/postal/test/message.clj | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/postal/message.clj b/src/postal/message.clj
index 929757f..7293222 100644
--- a/src/postal/message.clj
+++ b/src/postal/message.clj
@@ -23,10 +23,12 @@

 (ns postal.message
   (:use [clojure.set :only [difference]]
-        [clojure.java.io :only [file]]
+        [clojure.java.io :only [as-url as-file]]
         [postal.date :only [make-date]]
         [postal.support :only [do-when make-props message-id user-agent]])
   (:import [java.util UUID]
+           [java.net MalformedURLException]
+           [javax.activation DataHandler]
            [javax.mail Session Message$RecipientType]
            [javax.mail.internet MimeMessage InternetAddress
             AddressException]
@@ -61,6 +63,11 @@
     (into-array InternetAddress (map #(make-address % charset)
                                      addresses))))

+(defn- make-url [x]
+  (try (as-url x)
+       (catch MalformedURLException e
+         (as-url (as-file x)))))
+
 (defn message->str [msg]
   (with-open [out (java.io.ByteArrayOutputStream.)]
     (let [^javax.mail.Message jmsg (if (instance? MimeMessage msg)
@@ -97,8 +104,10 @@
 (defn eval-bodypart [part]
   (condp (fn [test type] (some #(= % type) test)) (:type part)
     [:inline :attachment]
-    (let [attachment-part (doto (javax.mail.internet.MimeBodyPart.)
-                            (.attachFile (file (:content part)))
+    (let [url (make-url (:content part))
+          attachment-part (doto (javax.mail.internet.MimeBodyPart.)
+                            (.setDataHandler (DataHandler. url))
+                            (.setFileName (re-find #"[^/]+$" (.getPath url)))
                             (.setDisposition (name (:type part))))]

       (when (:content-type part)
diff --git a/test/postal/test/message.clj b/test/postal/test/message.clj
index 64784c5..ef05240 100644
--- a/test/postal/test/message.clj
+++ b/test/postal/test/message.clj
@@ -24,11 +24,13 @@
 (ns postal.test.message
   (:use [postal.message]
         [clojure.test :only [run-tests deftest is]]
+        [clojure.java.io :as io]
         [postal.date :only [make-date]])
   (:import [java.util Properties UUID]
            [javax.mail Session Message$RecipientType]
            [javax.mail.internet MimeMessage InternetAddress
-            AddressException]))
+            AddressException]
+           [java.util.zip ZipOutputStream ZipEntry]))

 (deftest test-simple
   (let [m (message->str
@@ -81,8 +83,35 @@
                    {:type :attachment
                     :content f2}]})]
     (is (.contains m "tempfile"))
+    (is (.contains m (.getName f1)))
+    (is (.contains m "resolv.conf"))
+    (is (not (.contains m "etc")))
     (.delete f1)))

+(deftest test-attachments-from-url
+  (let [jar (doto (java.io.File/createTempFile "_postal-" ".jar"))
+        _ (with-open [zip-out (ZipOutputStream. (io/output-stream jar))
+                      zip-w (writer zip-out)]
+            (.putNextEntry zip-out (ZipEntry. "test-directory/test-filename.txt"))
+            (binding [*out* zip-w]
+              (println "tempfile contents")))
+        jar-url (str "jar:file:" (.getPath jar) "!/test-directory/test-filename.txt")
+        f-url "file:///etc/resolv.conf"
+        m (message->str
+            {:from "[email protected]"
+             :to "[email protected]"
+             :subject "Test"
+             :body [{:type :attachment
+                     :content jar-url}
+                    {:type :attachment
+                     :content f-url}]})]
+    (is (.contains m "tempfile"))
+    (is (.contains m "test-filename.txt"))
+    (is (not (.contains m "test-directory")))
+    (is (.contains m "resolv.conf"))
+    (is (not (.contains m "etc")))
+    (.delete jar)))
+
 (deftest test-attachment-with-custom-name-and-description
   (let [f1 (doto (java.io.File/createTempFile "_postal-" ".txt"))
         _ (doto (java.io.PrintWriter. f1)
-- 
1.8.5

Postal doesn't correctly support RFC6531 email addresses

RFC6531 email addresses still don't work in postal, #27 only addressed sender names and not email addresses.

(defn make-address
  ([^String addr ^String charset]
     (let [a (try (InternetAddress. addr)
                  (catch Exception _))]
       (if a
         (InternetAddress. (.getAddress a)
                           (.getPersonal a)
                           charset))))
  ([^String addr ^String name-str ^String charset]
     (try (InternetAddress. addr name-str charset)
          (catch Exception _))))

The three argument version of this code is not called by any postal code afaict, and the two argument version returns nil when given non-ascii characters as input, e.g.

(make-address "Tést <[email protected]>" "utf-8") ;; good
=> #<InternetAddress =?utf-8?Q?T=C3=A9st?= <[email protected]>>
(make-address "té[email protected]" "utf-8") ;; bad
=> nil
(make-address "té[email protected]" "Tést" "utf-8") ;; good, but never called
=> #<InternetAddress =?utf-8?Q?T=C3=A9st?= <té[email protected]>>

Don't use hardcoded sendmail paths

Why don't you just use the sendmail that's in $PATH?

I happen to use msmtp for outgoing mail and exim for local delivery... The way you've done it is it'll try to use exim (because that's what /usr/sbin/sendmail is symlinked to), and fail.

Also my msmtp is in /usr/bin not /usr/sbin.

New release please?

Hit @drewr

Thank you for this library. We use it at CircleCI and it works great. 👏

Could you make a new release of this library please? I'm trying to work around the issue that was fixed in #91 - but I'd rather pull in the upstream fix.

Thank you again.

Marc

Support nested multipart messages

MIME Multipart messages support nesting of content. This is required to things like provide an alternative encoded body with attachments. For instance, the following data structure should produce a message with two types of alternative content as well as an attached file:

{:from "[email protected]"
           :to "[email protected]"
           :subject "Test"
           :body [[:alternative
                   {:type "text/html"
                    :content "<b>some html</b>"}
                   {:type "text/plain"
                    :content "some text"}]
                  {:type :attachment
                   :content "/path/to/some/file/"}]}

`name` being used to stringify keywords

1-

In message.clj there's:

(defn add-extra! [^javax.mail.Message jmsg msgrest]
  (doseq [[n v] msgrest]
    (.addHeader jmsg (if (keyword? n) (name n) n) v))
  jmsg)

However name treats the slash / character as a delimiter.

For instance, the nonstandard header field as a keyword:

(send-message {:from "[email protected]"
               :to "[email protected]"
               :subject "Hi!"
               :body "Test."
               :X-ISO/IEC-ID-1 "test1"
               "X-ISO/IEC-ID-2" "test2"})

Is truncated to:

IEC-ID-1: test1
X-ISO/IEC-ID-2: test2

Maybe some sort of helper function like this to replace instances of name?

(defn k2s [k]
  (if (keyword? k)
    (subs (str k) 1)
    k))

2-

I wasn't sure, but it looks like slashes are valid characters for header fields according to the RFC.

Header fields are lines composed of a field name, followed by a colon
(":"), followed by a field body, and terminated by CRLF.  A field
name MUST be composed of printable US-ASCII characters (i.e.,
characters that have values between 33 and 126, inclusive), except
colon.

http://tools.ietf.org/html/rfc2822#section-2.2

Only bcc

Hi,

what if I what/need send only to bcc, without any "to" ?

it is possible ?

It should...

missing dependency activation.jar

Building postal requires activation.jar, or the build process will throw java.lang.NoClassDefFoundError: javax/activation/DataSource (message.clj:1).

Workaround: copy activation.jar into lib/.

DKIM signing

Is there an easy way to add a DKIM signature to an email before sending?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.