23

I am desiring to send an email in R with an attachment using gmail. I have found that sendmailR does not work with gmail because it requires authentication (I couldn't get it to work with gmail so I assume this to be true unless someone tells me I'm wrong , in which case I'll post the R output and error message for that). I found a code snippet found here (LINK). As the site suggests the code is not formatted to send attachments but I have got it to send an email. I'd like to extend this code to send attachments (in an email correspondence the author of this code was unable to extend the code to send attachments).

I want to send emails with R using gmail. I am a windows 7 user with the 2.14 beta version of R.

The code that sends emails but not attachments:

require(rJython) 
rJython <- rJython() 
rJython$exec( "import smtplib" ) 
rJython$exec("from email.MIMEText import MIMEText") 
rJython$exec("import email.utils") 

mail<-c( 
#Email settings 
"fromaddr = 'bigbird@gmail.com'", 
"toaddrs  = 'oscarthegrouch@gmail.com'", 
"msg = MIMEText('This is the body of the message.')", 
"msg['From'] = email.utils.formataddr(('sender name', fromaddr))", 
"msg['To'] = email.utils.formataddr(('recipient name', toaddrs))", 
"msg['Subject'] = 'Simple test message'", 

#SMTP server credentials 
"username = 'bigbird@gmail.com'", 
"password = 'pw'", 

#Set SMTP server and send email, e.g., google mail SMTP server 
"server = smtplib.SMTP('smtp.gmail.com:587')", 
"server.ehlo()", 
"server.starttls()", 
"server.ehlo()", 
"server.login(username,password)", 
"server.sendmail(fromaddr, toaddrs, msg.as_string())", 
"server.quit()") 

jython.exec(rJython,mail) 

Note this message is cross posted at talkstats.com. I did not receive a reply there (just members telling me they wish they could help). If I receive a workable solution i will also post it there as well.

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • 1
    try `install.packages("Rmail",repos="http://ms.mcmaster.ca/~bolker/R",type="source")` and see if that works for you (a small package I put together that I have not tested much, but it does do authentication) – Ben Bolker Oct 18 '11 at 11:58
  • @Ben I tried your edit using the following:`code` send.mail("hello", "me@gmail.com", "me@gmail.com", auth = TRUE, user = "me@gmail.com",host="smtp.gmail.com", passwd = "me", server="smtp.gmail.com", verbose = FALSE, port = 587) The code went into R but did not return an email to myself. Plus can your package send attachments? Anywhere there is a me I changed what I sent to mask personal info. – Tyler Rinker Oct 18 '11 at 22:15
  • I don't know how to enclose code. If someone lets me know how I'll edit my posts to make them more readable. There was an option in my original post but not in the follow up comments. I tired enclosing in ticks as the message suggests to do. – Tyler Rinker Oct 18 '11 at 22:21
  • No, it can't send attachments. It was too much trouble to code; I ended up using a system call to `mutt` when I wanted to do that. I don't know what went wrong with your attempt, but setting `verbose=TRUE` would probably provide more information ... – Ben Bolker Oct 18 '11 at 22:37
  • @Ben I used the verbose as you suggest but and included, but this is a moot point as it does not send attachments. [1] "220 mx.google.com ESMTP l1sm122965vdi.0\r\n" >> EHLO smtp.gmail.com [1] "250-mx.google.com at your service, [71.186.128.121]\r\n250-SIZE 35882577\r\n250-8BITMIME\r\n250-STARTTLS\r\n250 ENHANCEDSTATUSCODES\r\n" >> AUTH LOGIN [1] "530 5.7.0 Must issue a STARTTLS command first. l1sm122965vdi.0\r\n" >> dHlsZXIucmlua2VyQGdtYWlsLmNvbQA= [1] "502 5.5.1 Unrecognized command. l1sm122965vdi.0\r\n" >> cmlua3R3MTYA [1] "502 5.5.1 Unrecognized command. l1sm122965vdi.0\r\n" – Tyler Rinker Oct 18 '11 at 22:44
  • >> MAIL From: [1] "530 5.7.0 Must issue a STARTTLS command first. l1sm122965vdi.0\r\n" >> RCPT To: [1] "530 5.7.0 Must issue a STARTTLS command first. l1sm122965vdi.0\r\n" >> DATA >> hello >> . [1] "530 5.7.0 Must issue a STARTTLS command first. l1sm122965vdi.0\r\n" >> QUIT [1] "502 5.5.1 Unrecognized command. l1sm122965vdi.0\r\n" – Tyler Rinker Oct 18 '11 at 22:44

8 Answers8

17

You are running Jython code inside of your R environment, so you're looking for a way to send an attachment using the Jython language, not R.

Since Jython is basically Python, here is a way to send an email with an attachment with Python: How to send email attachments with Python.

You will just have to hack together that code into yours.

Community
  • 1
  • 1
Blender
  • 289,723
  • 53
  • 439
  • 496
  • 2
    Thank you for the direction. R I understand pretty well but I am no programmer. Until 3 days ago I'd never heard of Jython. I haven't the skill to splice the 2 together. Any further help would be appreciated. – Tyler Rinker Oct 18 '11 at 05:03
  • I tried your suggestions but am a bit thick. I think your suggestion is probably spot on since the original code I posted sends an email using gmail. To help me understand could you post again with an example of sending an email with an attachment using your code splice? That way i can see where the two codes are different and make the switch. I truly appreciate the attempts people are giving. The problem is with understanding on my end. Thanks in advance. – Tyler Rinker Oct 18 '11 at 22:27
  • This is the code piece that draws an error (I included the error). That's why i think I'm butcher what you've given me. If you post a second code as before with a sample of how you'd attach a file I will be able to see what I need to edit to make the code work. + "for f in ["C:/Users/Rinker/Desktop/PhD Program/CEP 529 Applied Regression Anal/NELS.csv":", Error: unexpected symbol in: " "for f in ["C" – Tyler Rinker Oct 18 '11 at 22:39
  • Sorry, I put a `:` instead of a `]` in the code. If you want, replace that `:` with a `]` on that line, or fill in your details again into this one: http://pastebin.com/raw.php?i=kP1RCRAL – Blender Oct 18 '11 at 23:54
  • I get this error now: Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, : SyntaxError: ("mismatched input '\\n' expecting COLON", ('', 8, 90, "\tfor f in ['C:/Users/Rinker/Desktop/PhD Program/CEP 529 Applied Regression Anal/NELS.csv']\n")) Perhaps I am trying to attach the file inappropriately. R uses backslashes so I converted the forward slashes. Is this a problem? Do I not put a file path here? – Tyler Rinker Oct 19 '11 at 00:12
  • You do, I just forgot the colon. Once more? http://pastebin.com/raw.php?i=rBN8RXR3 – Blender Oct 19 '11 at 00:22
  • I still get the error:Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, : SyntaxError: ("no viable alternative at input 'msg'", ('', 19, 29, "\tserver.sendmail(msg['From'] msg['To'], msg.as_string())\n")) I have placed the code I used here: [link](http://pastebin.com/RmyL2fdd) – Tyler Rinker Oct 19 '11 at 00:57
  • I'm beginning to think Jython and R hate one another, as this method of debugging code is not very effective ;) Sadly, I have no idea what this means. – Blender Oct 19 '11 at 01:25
  • thank you for your attempts. I'll try posting to r-help in a few days and see if I get a viable response there (provided I get no further help here). – Tyler Rinker Oct 19 '11 at 01:51
  • 1
    @TylerRinker You're getting an error because you're missing a comma between `msg['From']` and `msg['To']`. – blahdiblah Nov 06 '11 at 18:38
  • @Blender, yes see my last anser/response I happened upon from the rhelp mail list. It works very well. – Tyler Rinker Nov 12 '11 at 21:08
6

A response that works and works well is found here:
http://r.789695.n4.nabble.com/Email-out-of-R-code-td3530671.html

Thank you to nutterb for an answer from the rhelp list. Thank you to all that tried to assist me and were patient with my ignorance of python.

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • This solution works very well, even with custom Google Apps domains. – bshor Sep 07 '12 at 18:43
  • 1
    May I suggest you check out my package wrapper for the idea: https://github.com/trinker/gmailR – Tyler Rinker Sep 07 '12 at 18:58
  • The problem I am having (not using the package wrapper) is that I don't know how to add newlines in the message body. Adding "\n" doesn't seem to work, with the following error: "Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, : SyntaxError: ("mismatched character '\\n' expecting '''", ('', 4, 76, "\tmsg = MIMEText('Thank you for answering the 2012 Ideology Election Survey. \n"))" – bshor Sep 07 '12 at 22:08
  • Even worse, if the message body is too long, I get the same error. :( – bshor Sep 07 '12 at 22:48
5

Option 1: For sendmailR, it seems that you're having issues with the appending of port 25. You should be able to specify the destination port via sendmail_options(smtpPort = 587), prior to using the sendmail() command.

I am not sure that this will resolve your other issues, but it should get you the right port.


Option 2: If you'd like to invoke a Python script, this one looks most relevant. You may find it easiest to do token substitution, i.e. take a base script, put in strings that you'll simply find (i.e. the tokens) & replace (i.e. substitution with your desired strings), and then execute the revised script.

For instance, using the script at the link above (saved in a local directory as "sendmail_base.py"):

BasePy  = scan("sendmail_base.py", what = "character", sep = "\n")
OutPy = gsub("your_email@gmail.com", "yourRealEmailAddress", InFile)
OutPy = gsub("your_password", "yourRealPassword", OutFile)

and so on, replacing the header, recipient, etc., with the text strings you'd like to use, and the same for specification of the attachment file name. Finally, you can save the output to a new Python file and execute it:

cat(OutPy, file = "sendmail_new.py", sep = "\n")
system("chmod u+x sendmail_new.py; ./sendmail_new.py")

Although this is a very naive approach, it is simple and debugging of the script involves only examination of whether your output Python program is working and whether or not R is generating the right output Python program. This is in contrast to debugging what's going on with R passing objects to and from various packages and languages.

Iterator
  • 20,250
  • 12
  • 75
  • 111
3

I came across this code today from the rhelp listserve. Maybe it'll help things along:

send.email <- function(to, from, subject, message, attachment=NULL, username, password,
                   server="smtp.gmail.com:587", confirmBeforeSend=TRUE){
 # to: a list object of length 1. Using list("Recipient" ="recip@somewhere.net")       will     send the message to the address but
 # the name will appear instead of the address.
 # from: a list object of length 1. Same behavior as 'to'
 # subject: Character(1) giving the subject line.
 # message: Character(1) giving the body of the message
 # attachment: Character(1) giving the location of the attachment
 # username: character(1) giving the username. If missing and you are using Windows, R     will prompt you for the username.
 # password: character(1) giving the password. If missing and you are using Windows, R     will prompt you for the password.
 # server: character(1) giving the smtp server.
 # confirmBeforeSend: Logical. If True, a dialog box appears seeking confirmation         before sending the e-mail. This is to
 # prevent me to send multiple updates to a collaborator while I am working interactively.

 if (!is.list(to) | !is.list(from)) stop("'to' and 'from' must be lists")
 if (length(from) > 1) stop("'from' must have length 1")
 if (length(to) >  1) stop("'send.email' currently only supports one recipient e-mail     address")
 if (length(attachment) > 1) stop("'send.email' can currently send only one attachment")
 if (length(message) > 1){
 stop("'message' must be of length 1")
 message <- paste(message, collapse="\\n\\n")
 }

 if (is.null(names(to))) names(to) <- to
 if (is.null(names(from))) names(from) <- from
 if (!is.null(attachment)) if (!file.exists(attachment)) stop(paste("'",
attachment, "' does not exist!", sep=""))

 if (missing(username)) username <- winDialogString("Please enter your
e-mail username", "")
 if (missing(password)) password <- winDialogString("Please enter your
e-mail password", "")

 require(rJython)
 rJython <- rJython()

 rJython$exec("import smtplib")
 rJython$exec("import os")
 rJython$exec("from email.MIMEMultipart import MIMEMultipart")
 rJython$exec("from email.MIMEBase import MIMEBase")
 rJython$exec("from email.MIMEText import MIMEText")
 rJython$exec("from email.Utils import COMMASPACE, formatdate")
 rJython$exec("from email import Encoders")
 rJython$exec("import email.utils")

 mail<-c(
 #Email settings
 paste("fromaddr = '", from, "'", sep=""),
 paste("toaddrs = '", to, "'", sep=""),
 "msg = MIMEMultipart()",
 paste("msg.attach(MIMEText('", message, "'))", sep=""),
 paste("msg['From'] = email.utils.formataddr(('", names(from), "',
fromaddr))", sep=""),
 paste("msg['To'] = email.utils.formataddr(('", names(to), "',
toaddrs))",
sep=""), 
 paste("msg['Subject'] = '", subject, "'", sep=""))

 if (!is.null(attachment)){
 mail <- c(mail,
 paste("f = '", attachment, "'", sep=""),
 "part=MIMEBase('application', 'octet-stream')",
 "part.set_payload(open(f, 'rb').read())",
 "Encoders.encode_base64(part)",
 "part.add_header('Content-Disposition', 'attachment;
filename=\"%s\"' %
os.path.basename(f))",
 "msg.attach(part)")
 }

#SMTP server credentials
 mail <- c(mail, 
 paste("username = '", username, "'", sep=""),
 paste("password = '", password, "'", sep=""),

#Set SMTP server and send email, e.g., google mail SMTP server
 paste("server = smtplib.SMTP('", server, "')", sep=""),
 "server.ehlo()",
 "server.starttls()",
 "server.ehlo()",
 "server.login(username,password)",
 "server.sendmail(fromaddr, toaddrs, msg.as_string())",
 "server.quit()")

 message.details <-
 paste("To: ", names(to), " (", unlist(to), ")", "\n",
 "From: ", names(from), " (", unlist(from), ")",
"\n",
 "Using server: ", server, "\n",
 "Subject: ", subject, "\n",
 "With Attachments: ", attachment, "\n",
 "And the message:\n", message, "\n", sep="")

 if (confirmBeforeSend)
 SEND <- winDialog("yesnocancel", paste("Are you sure you want to send
this e-mail to ", unlist(to), "?", sep=""))
 else SEND <- "YES"

 if (SEND %in% "YES"){
 jython.exec(rJython,mail)
 cat(message.details)
 }
     else cat("E-mail Delivery was Canceled by the User")

Now I try it:

x<-paste(getwd(),"/Eercise 6.doc",sep="")
send.email(list("bigbird@gmail.com"), list("bigbird@gmail.com"), 'dogs', 
            'I sent it!', attachment=x, 'bigbird@gmail.com', 'mypassword',
                       server="smtp.gmail.com:587", confirmBeforeSend=FALSE)

AND THE ERROR:

> x<-paste(getwd(),"/Eercise 6.doc",sep="")
>send.email(list("bigbird@gmail.com"), list("bigbird@gmail.com"), 'dogs', 
+            'I sent it!', attachment=x, 'bigbird@gmail.com', 'mypassword',
+                       server="smtp.gmail.com:587", confirmBeforeSend=FALSE)
Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl,  : 
  SyntaxError: ("mismatched character '\\n' expecting '''", ('<string>', 15,  
      52, "\tpart.add_header('Content-Disposition', 'attachment;\n"))
Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
2

Take a look at the package sendmailR which can send attachments. To make sendmail work with gmail on a Mac would require some additional fiddling around, but you can find the instructions to do it using a google search.

Ramnath
  • 54,439
  • 16
  • 125
  • 152
  • 2
    The problem with sendmailR is that I've read it doesn't do authentication (which gmail requires) am I correct or incorrect on this? I've attempted to use sendmailR and get an error. Shall i post this? – Tyler Rinker Oct 18 '11 at 05:34
  • > from <- sprintf("me@gmail.com", Sys.info()[4]) > to <- "mer@gmail.com" > subject <- "Hello from R" > body <- list("It works!", mime_part(iris)) > sendmail(from, to, subject, body, + control=list(smtpServer="smtp.gmail.com:587")) Error in socketConnection(host = server, port = port, blocking = TRUE) : cannot open the connection In addition: Warning message: In socketConnection(host = server, port = port, blocking = TRUE) : smtp.gmail.com:587:25 cannot be opened – Tyler Rinker Oct 18 '11 at 11:07
  • I use sendmailR like this: sendmail(from, to, subject, msg, control=list(smtpServer="ASPMX.L.GOOGLE.COM"), headers=list("Content-Type"="text/html; charset=UTF-8; format=flowed")) – gd047 Oct 18 '11 at 14:20
  • @gd047. you are on a Mac or Windows. People have reported trouble using `sendmail` out of the box on a Mac. – Ramnath Oct 18 '11 at 15:53
  • I'm on windows. I tried it as you suggested and get the following input and error: > sendmail(from, to, subject, msg, control=list(smtpServer="smtp.gmail.com", smtpPortSMTP="587"), + headers=list("Content-Type"="text/html; charset=UTF-8; format=flowed")) Error in socketConnection(host = server, port = port, blocking = TRUE) : cannot open the connection In addition: Warning message: In socketConnection(host = server, port = port, blocking = TRUE) : smtp.gmail.com:25 cannot be opened – Tyler Rinker Oct 18 '11 at 22:21
  • How do I change the port to 587. This may be the key. I think gmail uses 587. I attempted but the error message indicates I was incorrect in changing the port. – Tyler Rinker Oct 18 '11 at 22:41
  • Typically, one specifies port with a colon: `yourhost.com:8080` or `yourserver.com:587`. – Iterator Oct 26 '11 at 02:09
1

You could give the new mailR package a shot that allows SMTP authorization: http://rpremraj.github.io/mailR/

The following call should then work:

27/05/14: Editing example below to demonstrate how attachments can be sent via R:

send.mail(from = "sender@gmail.com",
          to = c("recipient1@gmail.com", "recipient2@gmail.com"),
          subject = "Subject of the email",
          body = "Body of the email",
          smtp = list(host.name = "smtp.gmail.com", port = 465, user.name = "gmail_username", passwd = "password", ssl = TRUE),
          authenticate = TRUE,
          send = TRUE,
          attach.files = c("./download.log", "upload.log"),
          file.names = c("Download log", "Upload log"), # optional parameter
          file.descriptions = c("Description for download log", "Description for upload log"))
Rahul Premraj
  • 1,595
  • 14
  • 13
1

For working with Gmail using R best working example is available here. It's basic is as below:

  1. A project in Google Developers Console to manage your use of the Gmail API

  2. the gmailr R package by Jim Hester, which wraps the Gmail API (development on GitHub)

  3. the plyr and dplyr packages for data wrangling (do this with base R if you prefer)

  4. addresses.csv a file containing email addresses, identified by a key. In our case, student names.

  5. marks.csv a file containing the variable bits of the email you plan to send, including the same identifying key as above. In our case, the homework marks.

  6. the script send-email-with-r.r

pmr
  • 998
  • 2
  • 13
  • 27
0

Pasting here for convenience the code from one link above

send.email <- function(to, from, subject,
  message, attachment=NULL,
  username, password,
  server="smtp.gmail.com:587",
  confirmBeforeSend=TRUE){
  # to: a list object of length 1.  Using list("Recipient" = "recip@somewhere.net") will send the message to the address but
  #     the name will appear instead of the address.
  # from: a list object of length 1.  Same behavior as 'to'
  # subject: Character(1) giving the subject line.
  # message: Character(1) giving the body of the message
  # attachment: Character(1) giving the location of the attachment
  # username: character(1) giving the username.  If missing and you are using Windows, R will prompt you for the username.
  # password: character(1) giving the password.  If missing and you are using Windows, R will prompt you for the password.
  # server: character(1) giving the smtp server.
  # confirmBeforeSend: Logical.  If True, a dialog box appears seeking confirmation before sending the e-mail.  This is to
  #                    prevent me to send multiple updates to a collaborator while I am working interactively.  

  if (!is.list(to) | !is.list(from)) stop("'to' and 'from' must be lists")
  if (length(from) > 1) stop("'from' must have length 1")
  if (length(to) > 1) stop("'send.email' currently only supports one recipient e-mail address")
  if (length(attachment) > 1) stop("'send.email' can currently send only one attachment")
  if (length(message) > 1){
    stop("'message' must be of length 1")
    message <- paste(message, collapse="\\n\\n")
  }

  if (is.null(names(to))) names(to) <- to
  if (is.null(names(from))) names(from) <- from
  if (!is.null(attachment)) if (!file.exists(attachment)) stop(paste("'", attachment, "' does not exist!", sep=""))

  if (missing(username)) username <- winDialogString("Please enter your e-mail username", "")
  if (missing(password)) password <- winDialogString("Please enter your e-mail password", "")

  require(rJython)
  rJython <- rJython()

  rJython$exec("import smtplib")
  rJython$exec("import os")
  rJython$exec("from email.MIMEMultipart import MIMEMultipart")
  rJython$exec("from email.MIMEBase import MIMEBase")
  rJython$exec("from email.MIMEText import MIMEText")
  rJython$exec("from email.Utils import COMMASPACE, formatdate")
  rJython$exec("from email import Encoders")
  rJython$exec("import email.utils")

  mail<-c(
  #Email settings
  paste("fromaddr = '", from, "'", sep=""),
  paste("toaddrs  = '", to, "'", sep=""),
  "msg = MIMEMultipart()",
  paste("msg.attach(MIMEText('", message, "'))", sep=""),
  paste("msg['From'] = email.utils.formataddr(('", names(from), "', fromaddr))", sep=""),
  paste("msg['To'] = email.utils.formataddr(('", names(to), "', toaddrs))", sep=""),
  paste("msg['Subject'] = '", subject, "'", sep=""))

  if (!is.null(attachment)){
    mail <- c(mail,
      paste("f = '", attachment, "'", sep=""),
     "part=MIMEBase('application', 'octet-stream')",
     "part.set_payload(open(f, 'rb').read())",
     "Encoders.encode_base64(part)",
     "part.add_header('Content-Disposition', 'attachment; filename=\"%s\"' % os.path.basename(f))",
     "msg.attach(part)")
  }

#SMTP server credentials
  mail <- c(mail,
    paste("username = '", username, "'", sep=""),
    paste("password = '", password, "'", sep=""),

#Set SMTP server and send email, e.g., google mail SMTP server
    paste("server = smtplib.SMTP('", server, "')", sep=""),
    "server.ehlo()",
    "server.starttls()",
    "server.ehlo()",
    "server.login(username,password)",
    "server.sendmail(fromaddr, toaddrs, msg.as_string())",
    "server.quit()")

  message.details <-
    paste("To:               ", names(to), " (", unlist(to), ")", "\n",
          "From:             ", names(from), " (", unlist(from), ")", "\n",
          "Using server:     ", server, "\n",
          "Subject:          ", subject, "\n",
          "With Attachments: ", attachment, "\n",
          "And the message:\n", message, "\n", sep="")

  if (confirmBeforeSend)
   SEND <- winDialog("yesnocancel", paste("Are you sure you want to send this e-mail to ", unlist(to), "?", sep=""))
   else SEND <- "YES"

  if (SEND %in% "YES"){
    jython.exec(rJython,mail)
    cat(message.details)
  }
  else cat("E-mail Delivery was Canceled by the User")
} 
Julius Vainora
  • 47,421
  • 9
  • 90
  • 102
userJT
  • 11,486
  • 20
  • 77
  • 88