2004-04-20 10:08:52 UTC
I've taken a good look at the source code, and have a few comments on the implementation. I may be under the wrong impression in some respects, but I think you might want to reconsider how and when you handle events.
First, one of the great things about SPF (unlike some competing technologies) is the speed at which it can terminate an invalid connection. SPF needs only the "MAIL FROM:" command and does not even need the "DATA" section to read any headers. This is important, because there are significant bandwidth savings to this approach. Terminating the connection with an error not only saves bandwidth on individual messages, it also notifies the sender that they will no longer be able to send to the recipients in the future. If the sender is a spammer, then they (hopefully) will drop you from their spam list.
However, in your implementation, the parsing does not begin until the entire message has been fully received by the transport sink ("ISMTPOnArrival::OnArrival"). While I understand this is the easiest place to add the "Received-SPF" headers, it does not allow early termination of the connection. Indeed, by deleting the failures at the transport level instead of terminating them at the protocol level, the sender will not even realize that the mail did not transmit! If (heaven forbid) the sender was not a spammer, then this can lead to real problems.
Of course, you could send an NDR back to the sender, but that just eats up more bandwidth... plus if the sender is a spammer, the NDR may also bounce.
In addition, it appears to me that the transport level only receives the messages that flow through it (I could be wrong here). Will messages that never leave the SMTP protocol level (because they are relayed, for instance) be processed by SPF under the current scheme? Obviously, all relayed messages must be SPF processed before being relayed onto the destination host.
Finally, I think SPF's "Sender Rewriting Scheme" (which I'm sure you eventually plan to support) also needs to be applied at the SMTP protocol level, to allow rewritten messages to relay.
I propose the following solution:
Sink "ISmtpInCommandSink::OnSmtpInCommand", and perform the SPF parsing on the "MAIL FROM" command. I'm not sure, but it seems difficult to get the sender's IP address from the protocol event sink. I would hope that "IMMPID_MP_CONNECTION_IP_ADDRESS" would work at this point. If not, we could retrieve the address by sinking the responses to the "HELO/EHLO" commands, since the default response contains the real IP address of the sender in brackets.
If the resulting SPF action is "Drop the email", then terminate the connection with a
"550 5.7.1 please see
http://spf.pobox.com/why.html?sender=mengwong%40vw.mailzone.com&ip=208.210.125.24&receiver=dumbo.pobox.com"
error.
If the resulting action is not "Drop the email", then store the SPF result, rule, match, and explanation using the "ImailMsgProperties" interface. These can then be used later to create the headers.
Now comes the hard part… Take a look at the "Message Processing Flow" at the protocol level:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/smtpevt/html/_smtpevt_message_processing_flow.asp
ms-help://MS.VSCC/MS.MSDNVS/smtpevt/html/_smtpevt_message_processing_flow.htm
(for those of you with Visual Studio)
I think the best place to add the SPF headers would be at "IMailTransportSubmission::OnMessageSubmission".
And, I'm afraid the "IMailMsgProperties::ReadContent/WriteContent" or "IMailMsgProperties::MapContent/UnmapContent" will have to be used to add the SPF headers (using the properties stored from the SPF parsing done at the "MAIL FROM"). Not as easy as CDO, eh?
The only problem I see with this is that your "Recipient whitelist" won't work with early termination. Personally, I don't see much use for a recipient whitelist... A host whitelist (for relays) makes sense to me, but not a recipient whitelist. My "postmaster" and "abuse" get the most spam of any recipients, and I don't think any of the other implementations have it.
Let me know what you guys think. I'd be more than happy to help with this project in any way (including writing a configuration app).
Thanks,
Michael R. Brumm