4

I want to send a single mail to multiple recipients from R. I am able to achieve this using sendmail function but when recipients recieve the email, they see only their email address in to field. Looks like sendmail internally loops and sends individual emails to each recipient which is not a true carbon copy. It is important that each recipient sees all the recipients intended for their specific email (business requirement, because they need to reply to all recipients of this email). how can I achieve this using R?

my code

require(sendmailR)
to <- c("vasudeva.naik@abc.com")
header <- list(cc=c("alok.jadhav@abc.com"))
x <- sendmail("toto@abc.com", to, "test", "testing", header=header,control=list(smtpServer=server,verbose=TRUE))
<< 220 equity.xyz.com ESMTP Sendmail 8.11.7p1+Sun/8.11.7; Thu, 11 Jul 2013 21:31:43 -0400 (EDT)
>> HELO  HKD03836654
<< 250 equity.xyz.com Hello HKD03836654.gbl.ad.net [169.34.175.142], pleased to meet you
>> MAIL FROM:  toto@abc.com
<< 250 2.1.0 toto@abc.com... Sender ok
>> RCPT TO:  vasudeva.naik@abc.com
<< 250 2.1.5 vasudeva.naik@abc.com... Recipient ok
>> DATA
<< 354 Enter mail, end with "." on a line by itself
>> <message data>
<< 250 2.0.0 r6C1Vh101169 Message accepted for delivery
>> QUIT
<< 221 2.0.0 equity.csfb.com closing connection

Output from debug option. header information is not present in the debug output.

> sendmail("toto@abc.com", to, "test", "testing", header=header,control=list(smtpServer=server,transport="debug"))
From: toto@abc.com
To: vasudeva.naik@abc.com
Subject: test
Date: Mon, 15 Jul 2013 02:15:29 -0000
MIME-Version: 1.0
Content-Type: multipart/mixed;             boundary="1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707"

This is a message with multiple parts in MIME format.
--1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707
Content-Type: text/plain; format=flowed

testing
--1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707--

Thanks.

Alok
  • 3,160
  • 3
  • 28
  • 47
  • 1
    It's kind of important to mention which package you're using (I assume `sendmailR`). This also has nothing to do with the sendmail tag, which is about the Unix program. – Hong Ooi Jul 09 '13 at 05:05
  • 2
    Maybe adding `header = list(Cc = c("",""))` to `sendmail` works? – Julius Vainora Jul 11 '13 at 14:05
  • @Julius That is exactly what I was hoping to use, but unfortunately it is not working. I have tried it before. Not sure if syntaxt error! Somewhere i read that cc doesn't work in sendmailR :( – Alok Jul 12 '13 at 01:18
  • `http://ablejec.nib.si/pub/HowTo/HowTo-SendMail.pdf` mentions that cc option in sendmailR doesn't work. I sent mail using `verbose=TRUE`. I don't see CC option sent to SMTP server. – Alok Jul 12 '13 at 01:34
  • Yes, that function hides the CC part. I am not sure about SMTP details, but my another guess would be that CC option is sent in the wrong place: it is sent after the `DATA`, e.g. `DATA; cc: alok.jadhav@abc.com; MIME-Version: 1.0 Content-Type: multipart/mixed;...` (here I use `;` instead of new line). Should it be sent before `DATA`? See `sendmailR:::.smtp_submit_mail` for more details. – Julius Vainora Jul 12 '13 at 15:34
  • 1
    Try to use `headers=header` instead, because otherwise `cc` is ignored, at least in the output. – Julius Vainora Jul 15 '13 at 08:25
  • It actually worked! I can't believe after spending all this time, it was actually a typo. I feel sorry for taking up your time. `header=header` didn't give any error because of `...` arguments. – Alok Jul 15 '13 at 10:27
  • No problem, glad to hear that it worked. I will write it as an answer with some more details now. – Julius Vainora Jul 15 '13 at 11:01

5 Answers5

3

You need to combine all the real recipients and send the email to each one of the them separately. CC is just informational as such; leave it out and you get BCC So, for example:

to <- c("vasudeva.naik@abc.com")  # addresses for the "To" header
cc <- c("alok.jadhav@abc.com")    # addresses for the "CC" header
bcc <- c("...")                   # more addresses, but these won't be visible anywhere

recipients <- c(to, cc, bcc)  # need to send the email to everyone (FIXME: drop duplicates)
header <- list(cc=cc)         # let everyone know who else gets the mail

x <- sendmail("toto@abc.com", recipients, "test", "testing", header=header, control=list(smtpServer=server,verbose=TRUE))

If you want all addresses in the To header you could use header <- list(to=to) instead.

Note though, above is untested. Should work in theory, but sendmailR might have other plans wrt handling some of the arguments.


To elaborate on my earlier comment. There are two parts to sending email, SMTP that's the protocol for delivering the message to the recipients, and the message content itself.

SMTP that handles the delivery looks something like:

MAIL FROM: toto@abc.com
RCPT TO: vasudeva.naik@abc.com
DATA
<message content here, see below>
.

Note that the FROM and TO here match the arguments to the sendmail() function. That determines who receives the mail.

Now, the message content (well, just the headers) looks something like this:

From: no-reply@example.com
To: everyone@example.com
CC: everyone-else@example.com

And yes the From and To are completely different from the previous ones. This is what the recipients get and see, but it bears no relevance to who actually gets the email. That's why spam in your inbox appears as something you've sent to someone else, even though you're the actual recipient.

Tommi Komulainen
  • 2,830
  • 1
  • 19
  • 16
  • Thanks for detailed answer. I tried above approach but it doesn't show cc recipients in the received email. Infact only 1st email address in teh recipients list received the email. I am beginning to think that sendmailR implementation is not complete. I have sent an email to the maintainer of the package but yet to receive any response from him on this. Seems like a CC feature is altogether missing from sendmailR. – Alok Jul 15 '13 at 02:06
  • and also, above code didn't work. accepts only single recipient in `to` argument. `header` can have multiple recipients, but i thnk this information is not used anywhere. – Alok Jul 15 '13 at 05:53
  • hmm, yeah, things like `to` accepting only single recipient was what I meant by sendmailR having other plans. That's easily worked around with `for` though like @rentsy answered. Odd that the CC list would get stripped out from the headers though, why would sendmailR do such a thing? Oh well... – Tommi Komulainen Jul 15 '13 at 06:44
  • yes :(. I have updated my question with the output from `debug` mode. Nothing from CC appears in the debug output. I hope to hear from the developer of sendmailR soon. – Alok Jul 15 '13 at 07:56
  • You might want to capitalize cc as `Cc` -- it looks like [sendmailR collects recipients from the headers list](https://github.com/themel/sendmailR/blob/master/R/sendmailR.r#L136) (assuming that's the same version) Seems it also overwrites `To` header so there goes that part of my suggestion. – Tommi Komulainen Jul 15 '13 at 08:51
  • Tommi, I had a typo in my function call where i had to pass `headers` instead I was passing `header'. Because of `...` argument, this didn't raise any error and `header` was unused till the end. Its working fine as expected now. – Alok Jul 15 '13 at 10:29
3

The problem is caused by the usage of parameter header instead of headers. However, it is not that stupid typo as one might think. As we know, we can abbreviate parameter names when calling functions:

myfun <- function(xx = 1) print(xx)
myfun(x = 2)
# [1] 2

It is also possible when having ...:

myfun <- function(xx = 1, ...) print(xx)
myfun(x = 2)
[1] 2

But in this case we have a different and uncommon order of parameters:

sendmail(from, to, subject, msg, ..., headers = list(), control = list())

which not surprisingly cause such problems:

myfun <- function(..., yy = 1) print(yy)
myfun(y = 2)
[1] 1
Julius Vainora
  • 47,421
  • 9
  • 90
  • 102
  • funny how sometimes small mistakes go unseen. good catch Julius. Thanks. I was looking at wrong place all the time. Guess I need to work more on my concentration :( – Alok Jul 16 '13 at 00:38
2

Try:

> for (to in recipients) {
+ sendmail(from, to, subject, msg, control...
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
Rentsy
  • 378
  • 3
  • 12
  • 4
    I don't think that answers my question. I am able to send mail to multiple users.. but individual mails are sent to each user. they can't see other recipients in the mail. I want to send a single mail to all users. – Alok Jul 09 '13 at 04:38
  • I think this *does* answer the question. AFAIK `CC` is just a "cosmetic" line in the message header similar to Subject - or even `To`. It does not affect where the email is going to be delivered, that is determined by the `to` argument to the `sendmail()` call - leave out the header and you get the functional equivalent of `BCC`. But either way you'll still have to explicitly send the email to every single recipient separately. – Tommi Komulainen Jul 12 '13 at 07:52
  • @Tommi, my requirement is that when the recipient tries to `Reply All` on my email, all the recipients in my original email shoul receive the reply. But this information is missing in the email header. Above approach will send individual mails to each recipient and the header information will be missing and hence doesn't answer my question. I am able to send mail to multiple recipients but the header information is missing. – Alok Jul 15 '13 at 02:08
2

A couple of possibilities (untested):

  1. Put the list of recipients as the first line in your message body. Rather clunky, but it works. I've actually seen this done with a Bcc: field (which defeats the point of Bcc:, but never mind that).

  2. Instead of a vector of mail recipients, have your to argument be a single string containing all the recipients, separated by commas.

Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • 2nd option did not work. I tried comma, colon and space between addresses. nothing worked. I did not understand the first option here. Did you mean something like this `msg <- "alok@abc.com hello"` and then send msg as the body ? Could you show an example? Thanks. – Alok Jul 09 '13 at 07:11
  • I haven't used sendmailR, but I assume the message body is just a vector of text strings? Add another string at the beginning which contains all your recipients' addresses. – Hong Ooi Jul 09 '13 at 08:54
  • I tried as suggested for 1st option `msg <- c("alok@abc.com","hello")`. No change in output. I saw `alok@abc.com` in the message of the email body. `alok@abc.com` did not receive any email. Any suggestions? – Alok Jul 09 '13 at 09:24
  • I meant that if you put the addresses in the message body, then at least everybody can see who got the email. It won't actually change how sendmailR does things. Like I said, clunky. – Hong Ooi Jul 09 '13 at 09:39
  • oh. I got confused there. i guess that doesn't work for me. for example, when one of the recipients click on `Reply All`, its not going to work. Definitely need a different solution. – Alok Jul 10 '13 at 01:54
1

I have faced this problem before, would love to know a more direct solution, but the way I solved it was to create a distribution list and send a single mail to the distribution list. That way everyone sees and can reply all to the list. Hope this solves your problem.

Rohit Das
  • 1,962
  • 3
  • 14
  • 23
  • Thanks. That doesn't seem like a permanent solution to me. It will work when the groups are always defined. – Alok Jul 12 '13 at 01:35