19

I've had this noted down on some of my code for a while:

/**
 * Add a BCC.
 *
 * Note that according to the conventions of the SMTP protocol all
 * addresses, including BCC addresses, are included in every email as it
 * is sent over the Internet. The BCC addresses are stripped off blind
 * copy email only at the destination email server.
 *
 * @param string $email
 * @param string $name
 * @return object Email
 */

I don't remember where I got it from (possible source) but that shouldn't be relevant to this question. Basically, whenever I try to send an email with BCCs via SMTP the BCC addresses are not hidden - I've read the whole RFC for the SMTP protocol (a couple years ago) and I don't think I'm missing anything.

The strange thing is, if I send an email with BCCs using the built-in mail() function everything works just right and I've no idea why - I would like to roll my own email sender but I fail to understand this.

Can someone please shed some light into this dark subject?

Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • 1
    I've never done it successfully without just sending separate messages while re-using the same connection. Even when you get bcc to _work_ (which depends on how well the remote MTA is written), services like hotmail just consider it SPAM. I was thinking of making this an answer, but it doesn't exactly answer your question .. and i'm interested in something that works too. – Tim Post May 01 '10 at 14:31
  • @Tim Post: Thanks for your comment, that's also what I was doing with my current implementation... I hope someone comes up with a solution or at least could explain why this happens. – Alix Axel May 01 '10 at 14:36
  • 1
    Note, by 'successfully' , I mean 'works everywhere' instead of 'works on Google but not quite on foomail'. Buggy remote MTA's are at least _part_ of the reason that it breaks (or rather, the parsers that they use). – Tim Post May 01 '10 at 14:36
  • 1
    +1 For rolling your own email sender. – Stephano Mar 07 '13 at 04:55

2 Answers2

45

The BCC addresses are not stripped off at the destination email server. That's not how it works.

How SMTP actually works

  • The sender will send a list of RCPT TO commands to the SMTP server, one for each receiver email addresses, and this command does not distinguish whether the receiver is a normal To, CC or BCC type receiver.
  • Soon enough after calling the command that tells the SMTP server who's the sender, who's the server, and everything else, only then the sender will call the DATA command, in which will contain the content of the email - which consist of the email headers and body - the one that are received by email clients. Among these email headers are the usual from address, to address, CC address.
  • The BCC address is not shown to the receiver, simply because it's not printed out under the DATA command, not because the destination SMTP server stripped them away. The destination SMTP server will just refer to the RCPT TO for the list of email addresses that should receive the email content. It does not really care whether the receiver is in the To, CC or BCC list.
    Update (to clarify): BCC email addresses must be listed in the RCPT TO command list, but the BCC header should not be printed under the DATA command.

Quoting a part of the RFC that I think is relevant to your case:

Please note that the mail data includes the memo header items such as Date, Subject, To, Cc, From [2].

Rolling out your own email sender

A couple of years ago, I frankly think, is quite a long time back to assume that you still memorize end-to-end of RFC 821. :)

Amry
  • 4,791
  • 2
  • 23
  • 24
  • MTA's like Hotmail _do_ seem to care, but I suppose there's nothing we can do about that :) – Tim Post May 01 '10 at 15:06
  • Ahh if that's the case, then I wouldn't really know. Personally I don't have any real world working prototype of my own email sender. I simply remembered a bit about this SMTP when I researched it as part of my coursework in university back in year 2002. :) – Amry May 01 '10 at 15:27
  • My implementation does exactly that, I don't have the RFC 821 memorized - I just memorized that I did it right (spent 3 days testing and debugging one missing dot). – Alix Axel May 01 '10 at 15:33
  • Actually I just noticed that I'm sending To, CC and BCC in `RCPT TO` commands **but** I'm also sending them after the `DATA` command - including the BCC. – Alix Axel May 01 '10 at 15:37
  • @Tim Post: Is this also the case of your implementation? – Alix Axel May 01 '10 at 15:39
  • @Alix: I see. Have you checked to see any differences in the raw content (the email header + body) between the one that you send and the one that `mail()` sent and then maybe try to make yours the same? Or even using some free SMTP server application that can be installed in your machine that would allow you to check the whole "conversation" between the sender and the SMTP server (this is as far as I can give any opinion of my own, don't have enough knowledge to advise on how to further debug SMTP issues). – Amry May 01 '10 at 15:43
  • 1
    @Alix: I believe I stated in my third point that BCC shouldn't be printed as part of the `DATA` command but it should definitely appear in the `RCPT TO` list. – Amry May 01 '10 at 15:47
  • @Army: Indeed. I just saw that "bug" after sending my first comment. I'll try that and to track down the differences between my implementation and `mail()` although I believe I read somewhere that `mail()` opens a new SMTP connection for each one of the BCC addresses, kinda pointless after your description. That's one of the reasons I also asked Tom, since he said he reuses the same SMTP connection to send BCCs. – Alix Axel May 01 '10 at 15:57
  • @Alix: If I remember right, you will only need to open new connection per receiving SMTP server. If the addresses consist of, for example, people@yahoo.com and people@gmail.com, then definitely there must be a minimum of two connections opened - one for each receiving server. – Amry May 01 '10 at 16:03
  • @Alix, No, I specify them in `RCPT TO`. – Tim Post May 01 '10 at 16:05
  • @Tim: And they still show up? =( I was kinda hoping @Amry was right. – Alix Axel May 01 '10 at 16:09
  • @Army: I got it, I'll try what you said (in a couple of hours) and I'll get back to you. Thanks for the reply! – Alix Axel May 01 '10 at 16:14
  • 1
    @Alix: Another thing, when you send to two (or more) different servers, then you should also split the `RCPT TO` commands accordingly, i.e you wouldn't want to call `RCPT TO: people@gmail.com` when you are connecting to the yahoo.com SMTP server. – Amry May 01 '10 at 16:23
  • @Army: I know that but thanks for reminding me. I'm coding the whole thing from scratch ATM. – Alix Axel May 01 '10 at 16:29
  • @Army: Tried your approach and it works (at least with Gmail). – Alix Axel May 01 '10 at 20:09
  • @Alix: Another way to test SMTP without coding first - use telnet to connect to the server on the SMTP port and you can "SMTP chat" with the server and see the result along the way. – Amry May 01 '10 at 22:35
21

Very late, but the accepted answer is essentially wrong.

First off, SMTP has nothing to do with BCC. SMTP, as a protocol, is concerned only with a return path (the MAIL request), a list of recipients (the RCPT request), and the data to be transferred (the DATA request). If you want to send an email to somebody via SMTP, then you have to supply their address in a RCPT request, period.

The contents of an email - the DATA, effectively - are specified completely separately, in RFC2822. There's a lot of latitude in how BCC should be handled. The spec gives 3 ways of handling BCC, and in only one of them is the BCC stripped out while preparing the email. If I use Thunderbird as an email client, for example, and point it to an SMTP server, and then look at the message on the line, then I find that the Thunderbird BCC has gone (from the SMTP DATA), and the SMTP connection instead contains a standard RCPT request for the bcc'ed address. So, Thunderbird converts BCC to RCPT, but that's not the only way to do it.

Another place to handle BCC is at the MTA - in other words, whatever SMTP server your mail client is pointed to. Sendmail, for example, searches all of the To, Cc, and Bcc lines in the SMTP DATA, and then constructs an address list from those lines, and then removes the Bcc line. You can persuade Sendmail to keep the Bcc if you want to. If sendmail isn't the destination MTA, then it will connect to another MTA over SMTP, and send the recipient addresses via RCPT. In other words, if sendmail is the destination MTA, and it gets a Bcc, it will strip it out, contrary to Amry's statement.

There's also some confusion in the comments. You can specify RCPT addresses to any domain, not just a list of addresses in the same domain. The MTA has to look up the MX records for the destination domains to work out where to send everything. The google.com and yahoo.com statements are wrong.

Community
  • 1
  • 1
EML
  • 9,619
  • 6
  • 46
  • 78
  • 1
    I've used this answer as a basis to modify the [Rebol SEND](http://codereview.stackexchange.com/q/111395/46291) function to better handle both CC and BCC fields. My tests thus far show it to work as described. – rgchris Nov 21 '15 at 09:20
  • Whether the BCC is removed is up to software, not to the protocol. It is bad practise to rely on sendmail or any other else MTA to remove it, as long as you can surely remove it yourself. – Michael Chourdakis Aug 18 '16 at 22:17
  • Maybe SMTP servers don't remove the `Bcc` header because they don't have to. The accepted answer by Amry is perfectly correct. – rds Sep 20 '16 at 13:33
  • Amry's answer doesn't address the OP's question, so it's wrong. It contains some detail on SMTP operation, which is (a) not relevant, and (b) not correct, specifically where it states that "The BCC address is not shown to the receiver, simply because it's not printed out under the DATA command". It also fails to point out that the relevant RFC is 2822, nothing to do with SMTP. – EML Sep 21 '16 at 08:08