MailBee.NET can make use of DNS queries for these tasks:
Besides that, MailBee.NET lets you make various DNS queries directly. Although MailBee.NET SMTP component mainly serves the purposes of sending e-mail, its capabilities of making DNS queries can also be used to verify incoming e-mails in a number of ways (including the validation of the e-mail address and IP address of the message sender).
For instance, if your code needs to perform an extensive anti-spam check against incoming e-mails, verifying just DKIM/DomainKeys signatures might not be enough and you'd also want to make sure sending hosts have valid MX, PTR, and SPF records.
In most cases, you'll perform such checks against the domain part of "From" e-mail address. You can take it as follows:
we assume msg
is a MailMessage instance which represents the incoming e-mail message being examined.
However, "From:" e-mail address may be forged. Usually, you'll need to combine different methods to improve the reliability of anti-spam checks, such as to use reverse DNS check which is immune to e-mail address forging. See Get reverse DNS records with DNS PTR query topic for details.
Also, you can perform content filtering with MailBee.NET AntiSpam component which implements self-learning Bayesian filter. This component is included in MailBee.NET assembly. See BayesFilter class for details.
To make queries to RBL servers, you can use RblFilter class (you can find the sample code there as well).
To request the list of DNS MX names for the given domain, use Smtp.GetMXHosts method. It also properly handles the situation when the host does not have any MX records but has A record (in case if the MX domain for the host is the host itself).
This sample downloads the last e-mail from an account on a POP3 server, then checks if the "From" domain has the required MX records (or A record) to determine if at least the domain part of the "From:" address denotes an existing host. The return value of Smtp.GetMXHosts method isn't used, we just need to know if the DNS MX records for that host are there:
// Get the last message from the POP3 server. MailMessage msg = Pop3.QuickDownloadMessage( "mail.domain.com", "jdoe", "secret", -1); Smtp mailer = new Smtp(); // See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = true; mailer.Log.Filename = "C:\\Temp\\log.txt"; mailer.Log.Clear(); // Get ready for DNS MX lookup. mailer.DnsServers.Autodetect(); bool isDomainValid; try { // Make DNS query. We don't care for results. // If the method succeeds, the domain is OK. mailer.GetMXHosts(msg.From.GetDomain()); isDomainValid = true; } catch (MailBeeDnsNameErrorException) { // DNS server does not know this domain. isDomainValid = false; } catch (MailBeeDnsRecordsDisabledException) { // By default, caching DNS queries is on. If the domain // being requested is already in the cache and MailBee.NET // already knows it's invalid, no actual query will be made. isDomainValid = false; } if (isDomainValid) { Console.WriteLine("Valid domain"); } else { Console.WriteLine("Invalid domain"); }
' Get the last message from the POP3 server. Dim msg As MailMessage = Pop3.QuickDownloadMessage( _ "mail.domain.com", "jdoe", "secret", -1) Dim mailer As New Smtp() ' See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = True mailer.Log.Filename = "C:\Temp\log.txt" mailer.Log.Clear() ' Get ready for DNS MX lookup. mailer.DnsServers.Autodetect() Dim isDomainValid As Boolean Try ' Make DNS query. We don't care for results. ' If the method succeeds, the domain is OK. mailer.GetMXHosts(msg.From.GetDomain()) isDomainValid = True Catch e As MailBeeDnsNameErrorException ' DNS server does not know this domain. isDomainValid = False Catch e As MailBeeDnsRecordsDisabledException ' By default, caching DNS queries is on. If the domain ' being requested is already in the cache and MailBee.NET ' already knows it's invalid, no actual query will be made. isDomainValid = False End Try If isDomainValid Then Console.WriteLine("Valid domain") Else Console.WriteLine("Invalid domain") End If
Here and below, we assume that MailBee, MailBee.Pop3Mail, MailBee.SmtpMail and MailBee.DnsMX namespaces are already imported, MailBee.Global.LicenseKey is specified (directly in the code, or in app.config or web.config file). To learn more, refer to Import namespaces and set license key topic.
As you can see, the spam detection efficiency of this method is very low. The spammer can easily forge "From:" address and use an existing domain in it (e.g. fake_from_address@hotmail.com). It's more reliable to use spam filtering methods which examine the sender's IP address instead (as it cannot be forged).
For instance, you can use rDNS query to get the sender's domain name from its IP address and then get MX records for the "From:" domain name. If any of these MX records contain the domain name of the sender, this indicates the "From:" domain is not forged.
The opposite is not correct, however. If the sending host's domain does not appear in MX list of the "From:" domain, it may indicate the relay SMTP server of the sender and its SMTP MX server are different hosts. This is perfectly normal for large providers.
Thus, you can use the method described above only to confirm that certain e-mail is not spam. If this check is negative, you should try other methods before you can say the e-mail is spam.
Get SPF or DKIM ADSP records with DNS TXT query
MailBee.NET provides built-in support of DomainKeys/DKIM verification with advanced methods of DomainKeys class and a short-hand MailMessage.DomainKeysVerify method.
Still, you may need to get some DNS TXT records manually, including those used with SPF (Sender Policy Framework, RFC 4408) or DKIM ADSP (Author Domain Signing Practices, RFC 5617).
MailBee.NET does not provide built-in mechanisms for SPF and DKIM ADSP but allows you to easily extract their DNS information for a domain. Your application will only need to parse the text string returned.
Although many servers use SPF nowadays, no server implementing DKIM ADSP is known to the moment (at least all major e-mail providers like Gmail, Hotmail and Yahoo still didn't support it at the moment of writing).
The sample below gets TXT records for DKIM ADSP (no exception is thrown in case if not found) and also checks root TXT records of the domain and searches for SPF record there:
Smtp mailer = new Smtp(); // See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = true; mailer.Log.Filename = "C:\\Temp\\log.txt"; mailer.Log.Clear(); // Get ready for making DNS queries. mailer.DnsServers.Autodetect(); string[] records = null; try { // Get DKIM ADSP record (will likely to fail so ignore exceptions). records = mailer.GetTxtData("_adsp._domainkey.domain.com"); // Some servers do not claim error but return no records. Check this. if (records != null) { Console.Write("DKIM ADSP record:"); foreach (string rec in records) { // Should be only one such record (if any). Console.WriteLine(rec); } Console.WriteLine(); } } catch (MailBeeDnsNameErrorException) { } catch (MailBeeDnsRecordsDisabledException) { } // Get root TXT records (to filter SPF record from them). records = mailer.GetTxtData("domain.com"); if (records != null) { foreach (string rec in records) { if (rec.ToLower().StartsWith("v=spf1")) { // Should be only one such record (if any). Console.Write("SPF record: "); Console.WriteLine(rec); } } }
Dim mailer As New Smtp() ' See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = True mailer.Log.Filename = "C:\Temp\log.txt" mailer.Log.Clear() ' Get ready for making DNS queries. mailer.DnsServers.Autodetect() Dim records As String() = Nothing Try ' Get DKIM ADSP record (will likely to fail so ignore exceptions). records = mailer.GetTxtData("_adsp._domainkey.domain.com") ' Some servers do not claim error but return no records. Check this. If Not (records Is Nothing) Then Console.Write("DKIM ADSP record:") Dim rec As String For Each rec In records ' Should be only one such record (if any). Console.WriteLine(rec) Next rec Console.WriteLine() End If Catch e As MailBeeDnsNameErrorException Catch e As MailBeeDnsRecordsDisabledException End Try ' Get root TXT records (to filter SPF record from them). records = mailer.GetTxtData("domain.com") If Not (records Is Nothing) Then Dim rec As String For Each rec In records If rec.ToLower().StartsWith("v=spf1") Then ' Should be only one such record (if any). Console.Write("SPF record: ") Console.WriteLine(rec) End If Next rec End If
You can extend the sample with the analysis of what's in the SPF record (for instance, get an e-mail from a POP3 or IMAP server, then look the SPF record up for the IP address of the sender which you can find inMailMessage.TimeStamps collection).
See the next sample on how to extract IP addresses from time stamps (Received headers). However, these sample represent only very basics of DNS-based spam filtering. For instance, SPF record may contain IP address ranges or special tokens like "mx" which need some additional processing.
Reverse DNS queries (also known as rDNS or DNS PTR) are used in many popular methods of filtering spam. You can also make rDNS queries for other needs, such as network diagnostics.
For a very simple code sample, see Smtp.GetPtrData method documentation.
The next two topics provide the extensive samples of checking rDNS to filter spam. Both samples check the IP address of the sender (if available in the Received header) and perform a DNS PTR query on it. After that, the samples do different things:
This method is widely used by SMTP MX servers when they respond to the connection request from the sending party (which can be the relay SMTP server of the sender or the machine which directly sends e-mail).
An SMTP session starts with HELO or HELO command. The sending party issues a command like EHLO sending.host.com where sending.host.com must designate the external IP address or the external host name of the sending computer. In case if it's a host name, the SMTP MX server makes a reverse DNS query to resolve this host name into an IP address and makes sure the obtained IP address matches the actual IP address of the incoming connection.
As your application is not an SMTP MX server and does not accept connections from senders directly, it can only determine the incoming connection's IP address and HELO domain from the message headers if your SMTP MX server added them to the message before putting the message into your inbox. Most servers do this by adding a Received header. Still, the exact format depends on a particular server so you'll need to adapt the code for your particular server.
The console sample below gets the last e-mail in a POP3 e-mail account, extracts the sender's IP address and HELO/EHLO domain, and uses rDNS query to check if they match. The sample also correctly handles the situation when the HELO/EHLO domain is an IP address:
using System; using System.Net; using System.Text.RegularExpressions; using MailBee; using MailBee.Mime; using MailBee.Pop3Mail; using MailBee.SmtpMail; using MailBee.DnsMX; class Sample { static string MatchIPAddress(string ipAddrString) { return Regex.Match(ipAddrString, @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").ToString(); } // Examples of receivedFrom and the results. // // receivedFrom: [139.126.112.43] (helo=relay-5.company.com) // Results: ip=139.126.112.43, heloDomain=relay-5.company.com, heloIsIP=false. // // receivedFrom: [127.0.0.1] (account joe@my-pc.office HELO localhost) // Results: ip=127.0.0.1, heloDomain=localhost, heloIsIP=false. // // receivedFrom: [139.126.112.43] (helo=139.126.112.43) // Result: ip=139.126.112.43, heloDomain=139.126.112.43, heloIsIP=true. // // receivedFrom: 139.126.112.43 (helo=[139.126.112.43]) // Results: ip=139.126.112.43, heloDomain=139.126.112.43, heloIsIP=true. static bool GetIPAddressAndHeloValue(string receivedFrom, ref string ip, ref string heloDomain, ref bool heloIsIP) { Match m = Regex.Match(receivedFrom, @"((?'ip'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)|" + @"(?i:helo(=| )(?'helo'\[?(\w|-|\.)+\]?))|(.))+"); if (m.Groups["ip"].Length > 0) { ip = m.Groups["ip"].ToString(); if (m.Groups["helo"].Length > 0) { heloDomain = m.Groups["helo"].ToString(); // [127.0.0.1] => 127.0.0.1 if (heloDomain.StartsWith("[") && heloDomain.EndsWith("]")) { heloDomain = heloDomain.Substring(1, heloDomain.Length - 2); } // Is helloDomain value an IP address? heloIsIP = (MatchIPAddress(heloDomain).Length > 0); // Both IP address and hello domain found. return true; } } return false; } static void Main(string[] args) { // Get the last message from the POP3 server. MailMessage msg = Pop3.QuickDownloadMessage( "mail.domain.com", "jdoe", "secret", -1); Smtp mailer = new Smtp(); // See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = true; mailer.Log.Filename = "C:\\Temp\\log.txt"; mailer.Log.Clear(); // Get ready for making DNS queries. mailer.DnsServers.Autodetect(); string fromString = null; IPAddress ip = null; string fromIP = null; string fromHelloDomain = null; bool helloDomainIsIP = false; // Analyze the message we received from the POP3 server. if (msg.TimeStamps.Count > 0) { // Get the "from" part of the most recent Received header. fromString = msg.TimeStamps[0].From; Console.WriteLine("\"Received: from\" value: " + fromString); Console.WriteLine(); // Get IP address and hello domain. if (GetIPAddressAndHeloValue(fromString, ref fromIP, ref fromHelloDomain, ref helloDomainIsIP)) { Console.WriteLine("Received from IP: " + fromIP); Console.WriteLine("HELO/EHLO domain used by client: " + fromHelloDomain); Console.WriteLine("HELO/EHLO domain is IP address: " + helloDomainIsIP.ToString()); Console.WriteLine(); } else { Console.WriteLine("IP address and HELO domain not available"); return; } // Check if the value is really an IP address. if (IPAddress.TryParse(fromIP, out ip)) { Console.WriteLine("Sender's IP address: " + fromIP); Console.WriteLine(); // In case if HELO/EHLO parameter is also an IP address, // just make sure both IP addresses match. if (helloDomainIsIP) { // Is the IP address where the message came from the // same as the IP address in HELO/EHLO parameter? if (fromIP == fromHelloDomain) { Console.WriteLine("Both IP addresses match. Perfect!"); } else { Console.WriteLine("IP addresses do NOT match!"); } } else { string[] recs = null; try { // Perform reverse DNS check for the sender's IP address. recs = mailer.GetPtrData(fromIP); } catch (MailBeeDnsNameErrorException e) { Console.WriteLine("No rDNS for the host " + e.HostName); return; } catch (MailBeeDnsRecordsDisabledException e) { Console.WriteLine("The local cache states " + "there is no rDNS for the host " + e.Domain); return; } if (recs != null) { Console.WriteLine("Reverse DNS record(s) found."); Console.WriteLine(); foreach (string record in recs) { Console.WriteLine(record); if (record.ToLower() == fromHelloDomain.ToLower()) { Console.WriteLine("Perfect match!"); } else { Console.WriteLine(record + " does not match " + fromHelloDomain); } } } else { // Can happen if the DNS record exists but empty. Console.WriteLine( "No corresponding rDNS record found for " + fromIP); } } } } } }
Imports System Imports System.Net Imports System.Text.RegularExpressions Imports MailBee Imports MailBee.Mime Imports MailBee.Pop3Mail Imports MailBee.SmtpMail Imports MailBee.DnsMX Module Module1 Function MatchIPAddress(ByVal ipAddrString As String) As String Return Regex.Match(ipAddrString, _ "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").ToString() End Function ' Examples of receivedFrom and the results. ' ' receivedFrom: [139.126.112.43] (helo=relay-5.company.com) ' Results: ip=139.126.112.43, heloDomain=relay-5.company.com, heloIsIP=false. ' ' receivedFrom: [127.0.0.1] (account joe@my-pc.office HELO localhost) ' Results: ip=127.0.0.1, heloDomain=localhost, heloIsIP=false. ' ' receivedFrom: [139.126.112.43] (helo=139.126.112.43) ' Result: ip=139.126.112.43, heloDomain=139.126.112.43, heloIsIP=true. ' ' receivedFrom: 139.126.112.43 (helo=[139.126.112.43]) ' Results: ip=139.126.112.43, heloDomain=139.126.112.43, heloIsIP=true. Function GetIPAddressAndHeloValue(ByVal receivedFrom As String, _ ByRef ip As String, ByRef heloDomain As String, _ ByRef heloIsIP As Boolean) As Boolean Dim m As Match = Regex.Match(receivedFrom, _ "((?'ip'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)|" & _ "(?i:helo(=| )(?'helo'\[?(\w|-|\.)+\]?))|(.))+") If m.Groups("ip").Length > 0 Then ip = m.Groups("ip").ToString() If m.Groups("helo").Length > 0 Then heloDomain = m.Groups("helo").ToString() ' [127.0.0.1] => 127.0.0.1 If heloDomain.StartsWith("[") And heloDomain.EndsWith("]") Then heloDomain = heloDomain.Substring(1, heloDomain.Length - 2) End If ' Is helloDomain value an IP address? heloIsIP = MatchIPAddress(heloDomain).Length > 0 ' Both IP address and hello domain found. Return True End If End If Return False End Function Sub Main() ' Get the last message from the POP3 server. Dim msg As MailMessage = Pop3.QuickDownloadMessage( _ "mail.domain.com", "jdoe", "secret", -1) Dim mailer As New Smtp() ' See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = True mailer.Log.Filename = "C:\Temp\log.txt" mailer.Log.Clear() ' Get ready for making DNS queries. mailer.DnsServers.Autodetect() Dim fromString As String = Nothing Dim ip As IPAddress = Nothing Dim fromIP As String = Nothing Dim fromHelloDomain As String = Nothing Dim helloDomainIsIP As Boolean = False ' Analyze the message we received from the POP3 server. If msg.TimeStamps.Count > 0 Then ' Get the "from" part of the most recent Received header. fromString = msg.TimeStamps(0).From Console.WriteLine("""Received: from"" value: " & fromString) Console.WriteLine() ' Get IP address and hello domain. If GetIPAddressAndHeloValue(fromString, _ fromIP, fromHelloDomain, helloDomainIsIP) Then Console.WriteLine("Received from IP: " & fromIP) Console.WriteLine("HELO/EHLO domain used by client: " & _ fromHelloDomain) Console.WriteLine("HELO/EHLO domain is IP address: " & _ helloDomainIsIP.ToString()) Console.WriteLine() Else Console.WriteLine("IP address and HELO domain not available") Return End If ' Check if the value is really an IP address. If IPAddress.TryParse(fromIP, ip) Then Console.WriteLine("Sender's IP address: " & fromIP) Console.WriteLine() ' In case if HELO/EHLO parameter is also an IP address, ' just make sure both IP addresses match. If helloDomainIsIP Then ' Is the IP address where the message came from the ' same as the IP address in HELO/EHLO parameter? If fromIP = fromHelloDomain Then Console.WriteLine("Both IP addresses match. Perfect!") Else Console.WriteLine("IP addresses do NOT match!") End If Else Dim recs As String() = Nothing Try ' Perform reverse DNS check for the sender's IP address. recs = mailer.GetPtrData(fromIP) Catch e As MailBeeDnsNameErrorException Console.WriteLine("No rDNS for the host " & e.HostName) Return Catch e As MailBeeDnsRecordsDisabledException Console.WriteLine("The local cache states " & _ "there is no rDNS for the host " & e.Domain) Return End Try If Not (recs Is Nothing) Then Console.WriteLine("Reverse DNS record(s) found.") Console.WriteLine() Dim record As String For Each record In recs Console.WriteLine(record) If record.ToLower() = fromHelloDomain.ToLower() Then Console.WriteLine("Perfect match!") Else Console.WriteLine(record & _ " does not match " & fromHelloDomain) End If Next record Else ' Can happen if the DNS record exists but empty. Console.WriteLine( _ "No corresponding rDNS record found for " & fromIP) End If End If End If End If End Sub End Module
We assume your license key covers not only Smtp class but for Pop3 as well. The sample gets the e-mail to analyze from a POP3 server but you can get it from any source including an IMAP server.
As most of spam is being sent from home systems, not Internet servers, it's enough to check if the sending part has a "good-looking" host name. If it doesn't, we probably deal with a personal computer which sends spam.
How can we know that the host name "looks good"? Good question.
Good records are somewhat like "mail.server.net", "smtp20.mail-cluster.mx.domain.com", etc. They should not have IP-address-alike sequences in their names which are "101.92.140.39.dynamic.isp.com" or "cable-78-109-33-05.provider.net" (typical external host names of home systems as assigned by ISPs).
As you can see, it's quite an informal definition which just tries to exploit naming habits of Internet providers which tend to use some common patterns for host names they assign to their customers. That's why it's pretty hard to distinguish between "good" and "bad" hosts, and requires a lot of coding to implement this.
The method discussed in the previous topic is simpler to implement but it's more limited and won't allow detecting spam if a spam program uses the correct host name in EHLO. The method discussed here, however, goes deeper and checks if the host name of the sending party (even if it's correct) has the format which is more typical for home systems rather than for Internet servers.
The spam program can put whatever it wants into EHLO command but it can't change the public IP address and the public host name of the machine it's sending from. And if this name looks suspicious, it can't do anything with it.
By the way, that's why it's so important to have a valid DNS PTR record and a good-looking public host name for your server which sends e-mail. Otherwise, other hosts will consider you a spam source.
The console sample below performs reverse DNS check for the IP address from which the e-mail came to the destination server. Unfortunately, there is no well-defined standard of storing the sender's IP address in the message so that the exact code may differ for your particular server. Moreover, as already said above, there is no strict rule of what is a good DNS record and what is not.
This sample assumes the sender's IP address is contained in the most recent Received header, and "good" DNS record is somewhat like "mx.domain.com" while "56.32.104.9.provider.net" is not. The e-mail message to check is taken from a POP3 server:
using System; using System.Net; using System.Text.RegularExpressions; using MailBee; using MailBee.Mime; using MailBee.Pop3Mail; using MailBee.SmtpMail; using MailBee.DnsMX; class Sample { static string MatchIPAddress(string ipAddrString) { return Regex.Match(ipAddrString, @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").ToString(); } static void Main(string[] args) { Smtp mailer = new Smtp(); // See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = true; mailer.Log.Filename = "C:\\Temp\\log.txt"; mailer.Log.Clear(); // Get ready for making DNS queries. mailer.DnsServers.Autodetect(); // Get last message from the POP3 server. MailMessage msg = Pop3.QuickDownloadMessage( "mail.domain.com", "jdoe", "secret", -1); string ipAddrString = null; IPAddress ip = null; if (msg.TimeStamps.Count > 0) { ipAddrString = msg.TimeStamps[0].From; // Remove everything but IP address. ipAddrString = MatchIPAddress(ipAddrString); // Check if the value is an IP address. if (IPAddress.TryParse(ipAddrString, out ip)) { try { Console.WriteLine( "Sender's IP address is " + ipAddrString); Console.WriteLine(); // Perform reverse DNS check for this IP address. // Ignore "name not found" exceptions if failed // (this indicates spam with no valid rDNS). string[] recs = mailer.GetPtrData(ipAddrString); if (recs != null) { Console.WriteLine("Reverse DNS record found."); Console.WriteLine("Will report all records now."); Console.WriteLine("Records:"); foreach (string record in recs) { // Display the record found. We'll then check // if the record is "good" in terms of rDNS // spam checks. Console.Write(record); bool isGoodName = false; // If the record contains IP address, no good. ipAddrString = MatchIPAddress(record); if (ipAddrString == string.Empty) { string[] parts = record.Split('.'); // If no dot, this is a local name - no good. if (parts.Length > 1) { // Short name like mail.domain.com is good. if (parts.Length <= 3) { isGoodName = true; } else { int nonLetterCount = 0; isGoodName = true; // Check first two sections for // IP-address like things and digits. for (int i = 0; i < 2; i++) { // Check if looks like // "adsl-11-22-33-44". ipAddrString = parts[i].Replace('-', '.'); if (MatchIPAddress(ipAddrString) != string.Empty) { // IP-address-alike is not a // good record (home system). nonLetterCount = 0; isGoodName = false; break; } for (int j = 0; j < parts[i].Length; j++) { if (!char.IsLetter( parts[i][j])) { nonLetterCount++; } } } // Too much digits and dashes - no good. if (isGoodName && nonLetterCount >= 5) { isGoodName = false; } } } } if (isGoodName) { Console.WriteLine(" looks good (server host)"); } else { Console.WriteLine(" looks bad (home host?)"); } } } } catch (MailBeeDnsNameErrorException) { } catch (MailBeeDnsRecordsDisabledException) { } } } } }
Imports System Imports System.Net Imports System.Text.RegularExpressions Imports MailBee Imports MailBee.Mime Imports MailBee.Pop3Mail Imports MailBee.SmtpMail Imports MailBee.DnsMX Module Module1 Function MatchIPAddress(ByVal ipAddrString As String) As String Return Regex.Match(ipAddrString, _ "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").ToString() End Function Sub Main() Dim mailer As New Smtp() ' See in the log on how exactly MailBee.NET makes DNS queries. mailer.Log.Enabled = True mailer.Log.Filename = "C:\Temp\log.txt" mailer.Log.Clear() ' Get ready for making DNS queries. mailer.DnsServers.Autodetect() ' Get last message from the POP3 server. Dim msg As MailMessage = Pop3.QuickDownloadMessage( _ "mail.domain.com", "jdoe", "secret", -1) Dim ipAddrString As String = Nothing Dim ip As IPAddress = Nothing If msg.TimeStamps.Count > 0 Then ipAddrString = msg.TimeStamps(0).From ' Remove everything but IP address. ipAddrString = MatchIPAddress(ipAddrString) ' Check if the value is an IP address. If IPAddress.TryParse(ipAddrString, ip) Then Try Console.WriteLine("Sender's IP address is " & ipAddrString) Console.WriteLine() ' Perform reverse DNS check for this IP address. ' Ignore "name not found" exceptions if failed ' (this indicates spam with no valid rDNS). Dim recs As String() = mailer.GetPtrData(ipAddrString) If Not (recs Is Nothing) Then Console.WriteLine("Reverse DNS record found.") Console.WriteLine("Will report all records now.") Console.WriteLine("Records:") Dim record As String For Each record In recs ' Display the record found. We'll then check ' if the record is "good" in terms of rDNS ' spam checks. Console.Write(record) Dim isGoodName As Boolean = False ' If the record contains IP address, no good. ipAddrString = MatchIPAddress(record) If ipAddrString = String.Empty Then Dim parts As String() = record.Split("."c) ' If no dot, this is a local name - no good. If parts.Length > 1 Then ' Short name like mail.domain.com is good. If parts.Length <= 3 Then isGoodName = True Else Dim nonLetterCount As Integer = 0 isGoodName = True ' Check first two sections for ' IP-address like things and digits. Dim i As Integer For i = 0 To 1 ' Check if looks like ' "adsl-11-22-33-44". ipAddrString = _ parts(i).Replace("-"c, "."c) If MatchIPAddress( _ ipAddrString) <> _ String.Empty Then ' IP-address-alike is not a ' good record (home system). nonLetterCount = 0 isGoodName = False Exit For End If Dim j As Integer For j = 0 To (parts(i).Length) - 1 If Not _ Char.IsLetter( _ parts(i)(j)) Then nonLetterCount += 1 End If Next j Next i ' Too much digits and dashes - no good. If isGoodName And _ nonLetterCount >= 5 Then isGoodName = False End If End If End If End If If isGoodName Then Console.WriteLine(" looks good (server host)") Else Console.WriteLine(" looks bad (home host?)") End If Next record End If Catch e As MailBeeDnsNameErrorException Catch e As MailBeeDnsRecordsDisabledException End Try End If End If End Sub End Module
We assume your license key covers not only Smtp class but Pop3 as well. The sample gets the e-mail to analyze from a POP3 server but you can get it from any source including an IMAP server.
The idea is to get rDNS records and check what's in there. If the record looks like "12.34.65.111.users.provider.com" or "dsl-134-50-127-9.telecom.net", this is probably home machine (not a network server), and such machine should not try to send e-mail without relay server (and most likely it's a spam source).
Note that this example (though it's big) still just demonstrates the idea, it should not be used in production. Real-world reverse DNS check can be even much more complicated to allow for different formats of "Received" headers from which time stamps are taken, more sophisticated patterns of "good" and "not good" host names, etc.
Copyright © 2006-2024 AfterLogic Corporation. All rights reserved.