title: Gmail SMTP send unique copies to each recipient
body: <p>I have a question about using the Gmail API to send vs SMTP. I am working to switch to SMTP for sending instead of the API <a href="https://stackoverflow.com/a/25750013">so that we can set the Message-ID header</a> (the SMTP send path also seems to have itempotency which is awesome). Another alternative that would work for us is if the send draft API kept a stable Message-ID when sent, but that doesn't happen either.</p>
  <p>However, when we send via SMTP we've noticed that the BCC header must be stripped otherwise it's leaked to all participants (and the MSA will add BCC if you leave it out and specify additional RCPT TO mailboxes). Is there a way to get the behavior that the Gmail API provides where each recipient gets a unique BCC header? It seems that trying to replicate this over SMTP results in <a href="https://stackoverflow.com/q/30501826/">multiple copies of the email in your SENT folder</a>. It seems that is IS possible to do this, as Superhuman is able to send emails this way (they also customize the body of each email with a tracking pixel per recipient) and I know they are doing this over SMTP because they have a custom Message-ID header set. Additionally it seems that they insert the mail into the User's sent folder using the HTTP API's insert method (based on inspecting the Delivered header for the sender) - is there a way to send over SMTP but not have it added to the user's SENT folder? I've also verified via the history API it seems that Superhuman is not deleting mail (there are no delete events when sending).</p>
  <p>We're sending using the latest version of the Apache commons net SMTP client (v3.8).</p>
  <p>Here's a snippet that is resulting in multiple copies of the email in the SENT folder (note this has a few of our internal data models and classes sprinkled in there):</p>
  <pre class="lang-kotlin prettyprint-override"><code>    private fun sendOverSmtp(email: Email, accountAddress: EmailAddress, token: AccessToken) {
          val client = AuthenticatingSMTPClient()
          val tracker = SmtpCommandTracker()
          client.addProtocolCommandListener(tracker)
          try {
              client.connect(&quot;smtp.gmail.com&quot;, 587)
              verifySmtpCommand(client.replyCode)
              verifySmtpCommand(client.elogin(&quot;smtp.myserver.com&quot;))
              verifySmtpCommand(client.execTLS())
              // SEE: https://developers.google.com/gmail/imap/xoauth2-protocol#initial_client_response
              // This must be the primary account's email address
              val saslXOauth2 = &quot;user=${accountAddress.raw}\u0001auth=Bearer ${token.tokenValue}\u0001\u0001&quot;
              val base64EncodedAuthString = Base64.getEncoder().encodeToString(saslXOauth2.toByteArray(Charsets.UTF_8))
              // Send a raw command because the builtin auth command doesn't work with gmail.
              verifySmtpCommand(client.sendCommand(&quot;AUTH&quot;, &quot;XOAUTH2 $base64EncodedAuthString&quot;))
              fun sendToRecipients(email: Email, recipients: List&lt;Mailbox&gt;) {
                  verifySmtpCommand(client.setSender(accountAddress.raw))
                  for (recipient in recipients) {
                      verifySmtpCommand(client.addRecipient(recipient.address.raw))
                  }
                  val writer = client.sendMessageData()
                  // The use block here closes the writer as well.
                  WriterOutputStream(writer, Charsets.UTF_8).use { email.serialize(it, includeBcc = true) }
                  verifySmtpCommand(client.completePendingCommand())
                  verifySmtpCommand(client.rset())
              }
              sendToRecipients(email.copy(bcc = emptyList()), email.to + email.cc)
              for (bcc in email.bcc) {
                  sendToRecipients(email.copy(bcc = listOf(bcc)), listOf(bcc))
              }
              verifySmtpCommand(client.quit())
          } catch (e: SmtpCommandError) {
              throw SmtpException(tracker.lastCommand, client.replyCode, client.replyString)
          } finally {
              client.disconnect()
          }
      }
  </code></pre>