Removing Read Receipts

Archived Content

This article was written a long time ago and it is no longer being maintained. The contents may not be relevant and links may not work. Thank you for your understanding.

How to remove read receipt requests on the server?

Read Recipient Removal Script
The source code discussed in the article. The ZIP package also contains the required smtpreg.vbs event administration script.
Download

Essential knowledge

To understand this article you need to be familiar with mail message formats and one of the VBScript / JScript languages. We will also learn a few things about Collaboration Data Objects for Windows® 2000 and its transport event sink support.

What is this article about?

It is a frequently asked question on the Microsoft Exchange 2000 newsgroups how could the server administrator disable sending read receipts back to the originator?

Some messaging clients—such as Microsoft Outlook 2000—automatically send read receipts, without asking the user if he want to send the read receipt or not. Some other clients—Microsoft Outlook Express—ask the user whether to send the receipt, some others can even completely turn off receipt sending (Outlook XP already supports this feature).

The time you read your mail is a question of privacy that you may not want to share with the mail sender or you have a reason for not wanting to send read receipts.

So if the messaging client does not support turning off the read receipt sending, it would be a good idea to turn it off on the server, wouldn't it? Not to worry you do not have to start the Exchange System Manager — Exchange 2000 does not support it by default.

Nevertheless, the Exchange 2000 architecture is very flexible and quite modular. There are two important things you should know now. The first is that Exchange 2000 uses the IIS SMTP service for SMTP communication. The second is that the IIS SMTP service supports programmatic manipulation of mail when a specific event occurs.

In other words, it is possible to write a simple script that removes the read receipt requests from the incoming mails.

This article describes the steps of writing that script.

Read receipt requests

It is quite evident that the read receipt request comes in the header of the mail to which the receipt is requested.

Want to do a little research? Send a mail with a read receipt request from an address to another. You will see one or two suspicious header fields such as the Read-Receipt-To: and Disposition-Notification-To: fields.

From: "Test User" <[email protected]>
To: "Peter Karsai" <[email protected]>
Read-Receipt-To: "Test User" <[email protected]>
Disposition-Notification-To: "Test User" <[email protected]>
Subject: Read Receipt Header Test

RFC2298 (An Extensible Message Format for Message Disposition Notifications) introduced the Disposition-Notification-To: header field in 1998, although it was already widely used on the Internet, just as the non-standard Read-Receipt-To: field. That is why some mail clients send both header fields.

If we want to remove the read receipt requests, all we have to do is to simply delete the two fields above. Sounds as quite an easy task and as you will see, really is simple.

CDOSYS SMTP Transport Event Sinks

The Collaboration Data Objects for Windows 2000 (also called CDOSYS) helps us to write scripts that are executed when a specific SMTP transport event occurs.

These scripts are extremely useful when you have to customize your mail system.

In this specific case we need an event that is executed when a mail arrives. This is lucky, because this is the only SMTP transport event that CDOSYS supports. The OnArrival transport event is called when a new mail is submitted to the SMTP transport system, this occurs, when a new incoming or outgoing mail arrives to the SMTP server, but before the server performs further processing on the mail.

The event code can be written in any programming language that supports implementing COM interfaces, but CDOSYS is so great to us that it also provides scripting support in any ActiveScript language (by default, these are VBScript and JScript).

Implementing the Event Sink script

To write the backbone of the event script, just choose a scripting language. We will provide all of our examples in both VBScript and JScript.

VBScript

<SCRIPT language="VBScript">
  Const cdoRunNextSink = 0

  Sub ISMTPOnArrival_OnArrival(ByVal Msg, EventStatus)
    ' event sink code comes here
    ...
    ' continue execution with the next sink
    EventStatus = cdoRunNextSink
  End Sub
</SCRIPT>

JScript

<SCRIPT language="JScript">
  var cdoRunNextSink = 0;

   function ISMTPOnArrival::OnArrival(Msg, Status) {
     // event sink code comes here
    ...
     // continue execution with the next sink
     Status = cdoRunNextSink;
   }
</SCRIPT>

As you might have already noticed, we receive a Msg parameter in the event. The Msg parameter is a CDO.Message (IMessage) object that represents the incoming/outgoing mail. All we have to do is to modify this object by removing the two fields mentioned above.

Take a moment to visit MSDN and look at the Fields collection (it is an ADODB.Fields collection) of the CDO.Message object. With the help of this collection, you can freely modify the message header, add new header fields, modify their values or even delete them.

Any field can be referenced in the form of "urn:schemas:mailheader:<fieldname>", e.g. "urn:schemas:mailheader:subject" references to the subject of the message.

So what about this: Msg.Fields.Delete("urn:schemas:mailheader:Disposition-Notification-To")? Yes, this will delete the Disposition-Notification-To: field from the message header. We only have to apply the changes we made to the mail.

The final event sink code now looks like:

VBScript

<SCRIPT language="VBScript">
  Const cdoRunNextSink = 0

  Sub ISMTPOnArrival_OnArrival(ByVal Msg, EventStatus)
    ' remove read receipt request fields
    Set Flds = Msg.Fields
    With Flds
      .Delete("urn:schemas:mailheader:Disposition-Notification-To")
      .Delete("urn:schemas:mailheader:Read-Receipt-To")
      ' update the mail header
      .Update
    End With

    ' save changes to the mail
    Msg.Datasource.Save

    ' continue execution with the next sink
    EventStatus = cdoRunNextSink
  End Sub
</SCRIPT>

JScript

<SCRIPT language="JScript">
  var cdoRunNextSink = 0;

  function ISMTPOnArrival::OnArrival(Msg, Status) {
    // remove read receipt request fields
    Msg.Fields.Delete("urn:schemas:mailheader:Disposition-Notification-To");
    Msg.Fields.Delete("urn:schemas:mailheader:Read-Receipt-To");

    // update the mail header and save changes
    Msg.Fields.Update();
    Msg.Datasource.Save();

    // continue execution with the next sink
    Status = cdoRunNextSink;
  }
</SCRIPT>

Registering the event sink

There are only two questions left.

First of all, we have to register the sink with the SMTP server somehow, and then we have to be able to tell the difference between incoming and outgoing mail, if it is important.

To register the event sink, Microsoft released a sample script file, the smtpreg.vbs available in MSDN. You can also download this file from our site. To register the event sink, run smtpreg.vbs as:

cscript smtpreg.vbs /add 1 onarrival <sinkname> CDO.SS_SMTPOnArrivalSink
    "rcpt to=*"
cscript smtpreg.vbs /setprop 1 onarrival <sinkname> Sink
    ScriptName "<path_to_scriptfile>"

The first command registers the OnArrival event sink and the second assigns our script to the OnArrival event sink.

If you take a closer look at the first command, you can see the "rcpt to=*" parameter, which is a rule. The SMTP server will execute the event only if the rule is evaluated to be true. In this case, the event will be executed everytime, because no restriction was made to the recipient.
To differentiate between incoming and outgoing mail, list you local domain(s) here.

So, if your script file is "c:\receiptscript\readreceiptrequestremoval.js" and you have two domains, somewhere.com and somewhere.net, you registration command should look like this:

cscript smtpreg.vbs /add 1 onarrival ReadReceiptSink CDO.SS_SMTPOnArrivalSink
            "rcpt to=*@somewhere.com;rcpt to=*@somewhere.net"

cscript smtpreg.vbs /setprop 1 onarrival ReadReceiptSink Sink ScriptName
    "c:\receiptscript\readreceiptrequestremoval.js"

Limitations

There are some known limitations of this script, it cannot remove read receipt requests from Rich Text messages and internal mails. IvaSoft has a commercial solution called Read Receipt Remover for Exchange 2000 that supports these features.

Conclusion

Now you can see how powerful the event support of the Windows 2000 IIS SMTP Service is. You can utilize these events to add disclaimers or even to create a full-featured mailing list, as I have done a few months ago.

If you are a network administrator, I recommend you to read MSDN topics about CDO messaging—as these are the features that make the Exchange 2000 architecture really extendible and configurable.

hnp1 | hnp2