Message Boards Message Boards

Send email with SendMail or an external delivery service?

If you have a small number of customers with whom you regularly email back and forth, then you’re going to know pretty quickly if there’s a problem with email delivery. In this low volume high and delivery confidence case the Wolfram Language SendMail function is a very good solution, regardless whether email is being sent from your Mathematica desktop, from the Wolfram Development Platform (public cloud), from a private Wolfram Cloud, or from CDF documents that run on a customer’s desktop.

On the other hand, if your business sends, or aspires to grow to a size where it sends, thousands of transactional and marketing emails per day, an email delivery service may give a much better delivery success rate, see for example the Mailgun documentation Email Best Practices guide, which explains how a delivery service manages domain and IP reputation and authentication, handles bounce feedback and unsubscribes, tracks recipient engagement, etc. Regardless of the choice to use SendMail or an email delivery service, be sure to always “send something people want.”

If you’d like to try out an email delivery service, the Mailgun API is easy to call from your desktop or from the Wolfram Development Platform. It takes only a few minutes to create a free account. The signup success page invites you to send a sandbox server test email and even gives cURL code with your name, sandbox domain, email address, and password already entered:

curl -s --user 'api:YOUR-PRIVATE-API-KEY' \
https://api.mailgun.net/v3/YOUR-SANDBOX-DOMAIN-NAME/messages \
-F from='Mailgun Sandbox <postmaster@YOUR-SANDBOX-DOMAIN-NAME>' \
-F to='YOUR-NAME <YOUR-EMAIL-ADDRESS>'\
-F subject='Hello YOUR-NAME' \
-F text='Congratulations YOUR-NAME, you just sent a Mailgun email!'

Simple extensions of this cURL code will add html and attachments to the test email. Cut and paste the appropriate cURL elements into a the MultipartElements option of a Wolfram Language URLFetch command and deploy on the Wolfram Development Platform:

With[{image=Image[Graphics[{Disk[{0,0}, Sqrt[2]], Red, Disk[]}], ImageSize->64]},
   CloudDeploy[Delayed[URLFetch["https://api.mailgun.net/v3/YOUR-SANDBOX-DOMAIN-NAME/messages",
      "Method"->"POST",
      "MultipartElements" -> {
         {"from","text/plain"} -> "Mailgun Sandbox <postmaster@YOUR-SANDBOX-DOMAIN-NAME>",
         {"to","text/plain"} -> "YOUR-NAME <YOUR-EMAIL-ADDRESS>",
         {"subject","text/plain"} -> "Hello YOUR-NAME",
         {"text","text/plain"} -> "Congratulations YOUR-NAME, you just sent a Mailgun email!",
         {"html","text/plain"} ->
            "<html> HTML version of the body <img alt=\"Bullseye\" src=\"data:image/jpeg;base64, " <>
            ExportString[image,{"Base64","JPEG"}] <> "\" /> </html>",
         {"attachment\"; filename=\"Bullseye.jpg","image/jpeg"} ->
            ExportString[image,"JPEG"]},
      "Username"->"api","Password"->"YOUR-PRIVATE-API-KEY"]], 
   FileNameJoin[{$CloudRootDirectory,"MailgunEmailDelivery"}]]]
URLExecute[%]

The last Multipart element name is "attachment" but URLFetch is tricked into adding the filename "Bullseye.jpg" by hiding it within a longer element name. You can deploy this URLFetch to a free account on the Wolfram Development Platform. And Mailgun is easily configured to send email from your own domain. It’s that simple! You’ll be up and running in a few minutes.

The above code computes both the HTML inline image and the attachment from a Wolfram Language image:

ExportString[image, {"Base64","JPEG"}]
ExportString[image, "JPEG"]

To instead import the inline image and attachment from a file, substitute Wolfram Language expressions:

ExportString[Import[file, "String"], "Base64"]
Import[file, "String"]

11/17/15 update of original 3/27/15 Wolfram Community post:

The above Wolfram Language code has been updated to post multipart/form-data with HTML email body and an attachment. Though URLFetch does not currently support the RFC 7578 multipart/form-data section 4.2 Content-Disposition "filename" parameter, Zach Bjornson recently published a hack that gets around this limitation. The URLFetch update uses this hack to send the attachment.

This Wolfram Community post was originally a “Share an Idea” comment titled: “Simple inexpensive delivery service outperforms SendMail.” It was written from the perspective of a small developer who sends a peak of no more than dozens of test emails per day, but who aspires to send thousands of emails per day. Though the insights offered remain valid, it seems more important to gather the emailing experiences of the larger Wolfram Community, both those currently sending email at relatively low volume and those already sending at higher volumes. Accordingly I’ve turned this into an “Ask a Question” post: “Use SendMail or an external email delivery service?” I invite people to share their experiences with either Wolfram Language SendMail or with external email delivery services.

8 Replies

Christopher, thanks for sharing. If I am not mistaken this adds html formatted mail.

Yes, all mail services will handle HTML formatted email. For a simple Mailgun example see Manual > Sending Messages > Sending via API. The example cURL HTML string is added to the MultipartElements option of the Wolfram Language URLFetch. Preserve and enhance the reputation of your domain (and IP address) by sending both text and HTML or text only, see Email Best Practices > Email Content.

Christopher,
I have tested your mail solution and it works. Then I went on trying to add "inline" html image and "attachments". Both need to be formatted like inline="@files/filename.jpg" or attachments="@files/filename.jpg". The "inline" must be very easy. I suspect the "attachment" is probably a little more difficult because it needs multipart/form-data.

in urlfetch i found "MultipartElements" -> {{"partName", "mime/type", {1, 2, 3, 4, 5}}}

can you help me solve how to do this?

Posted 10 years ago

If it is better, why wouldn't SendMail[] be modified to work like this?

POSTED BY: Sandu Ursu

The following URLFetch must be almost right. the error message is

 { "message": "'from' parameter is missing"}

This is the command used:

URLFetch["https://api.mailgun.net/v3/sandboxYOURID.mailgun.org/\
 "Parameters" -> 
  {
   "from" -> "Mailgun Sandbox<postmaster@sandboxYOURID.mailgun.org>",
   "to" -> "emailname<emailaddress>",
   "subject" -> "Hello",
   "text" -> "Congratulations message has been send",
   "html" -> 
    "<html> <center> HTML version of the body <img src='cid:pdfpicture.jpg'></center></html>"
   },
 "MultipartData" -> {{"inline", "multipart/form-data" , Import["pdfpicture.jpg", "Byte"]} },
 (*"JSON", *)
 "Method" -> "POST", 
 "Username" -> "api",
 "Password" -> "key-YOURKEY"
 ]

If I use getpostman.com to check my API command it works fine. There must be a syntax error in my URLFetch lines.

note: in mma9 "MultipartData" was used in mma10.1 use "MultipartElements"

Whether it's better to use SendMail or an email delivery service will depend on your application. Right now the delivery service is likely the only solution if you need to send thousands of emails per month, anticipate even higher future volumes, and want to send from your own domain to many different destination email addresses. I heartily agree with your suggestion to enhance SendMail. Indeed there could be quite an opportunity for a strategic alliance between Wolfram Research and an email delivery service provider: Wolfram would gain highly specialized expertise in delivering email against the ever evolving background of spammers and countermeasures. The delivery service provider might gain a lot of new users from Mathematica and Wolfram Cloud applications.

Pieter van Bijnen points out the importance of sending email in HTML format and including inline images. Accordingly, I’ve updated the code in my original post to demonstrate such an email.

Also, don’t delay setting up your own email domain. The code in my original post sends an email from the Mailgun sandbox domain. But all your test, development, and production code should send email from your own domain. Domain setup consists of two simple steps. First, generate DNS zone file TXT, CNAME, and MX records: login to Mailgun (or whichever email delivery service you’ve chosen), follow the link to add a new domain, and enter a subdomain name. Second, enter these records into the DNS zone file for your domain: login to your domain hosting account and follow the appropriate links to add zone file records. Other than entering these records, subdomain setup does not involve any other actions on the domain hosting account. If you’re building applications that do both bulk marketing and transactional email, then keep their email reputations separate by setting up different email domains for each.

I'm working in an implementation of Mailgun API for Mathematica. Just to leave a note for future readers, I discovered that Base64 are not supported in Gmail and Outlook, as you can check here.

POSTED BY: Rodrigo Murta
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract