This seems to be the right place to ask this question.
I'm trying to send a simple email message using the SmtpClient in system.net.mail through my own Postfix mail server. I've got UCE controls turned on and the .Send method is rightfully failing during the HELO negotiation because the FQDN of the sending host is not being sent. I don't see anywhere to force this behavior, or to otherwise set the FQDN on the SmtpClient object.
I'm missing something somewhere.
Sean

system.net.mail.smtpclient fqdn required
GetOuraThatGarden
Sabaawy
Thanks for making this suggestion, Richard.
I'd like to suggest a change in wording. The problem statement says:
The current implementation of the System.Net.Mail.SmtpClient
uses the NetBIOS name of the computer in the HELO / EHLO
commands. Many anti-spam systems require the FQDN instead.
As a result, email sent with the SmtpClient class is often blocked.
In fact, this behavior is required by the SMTP RFC, 821. I think that defining the problem in terms of specification compliance is a stronger argument for the change.
Sean
Niels Flensted
"A domain name that is not in FQDN form ... MUST NOT appear in any SMTP transaction."
I've updated the suggestion to include this information.
Andrewyyy
Ach, 2821, right, that's what I meant! :)
Thanks for ammending the request. It's certainly much more precise.
I'll look forward to a correctly functioning smtpclient someday! ;)
Sean
MorB
Until Microsoft fix the SmtpClient, the only solution is to use reflection to change the private "localHostName" field to the FQDN:
using System;
using System.Net.Mail;
using System.Net.NetworkInformation;
using System.Reflection;
namespace Trinet.Net.Mail
{
/// <summary>
/// An extended <see cref="SmtpClient"/> which sends the
/// FQDN of the local machine in the EHLO/HELO command.
/// </summary>
public class SmtpClientEx : SmtpClient
{
#region Private Data
private static readonly FieldInfo localHostName = GetLocalHostNameField();
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="SmtpClientEx"/> class
/// that sends e-mail by using the specified SMTP server and port.
/// </summary>
/// <param name="host">
/// A <see cref="String"/> that contains the name or
/// IP address of the host used for SMTP transactions.
/// </param>
/// <param name="port">
/// An <see cref="Int32"/> greater than zero that
/// contains the port to be used on host.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="port"/> cannot be less than zero.
/// </exception>
public SmtpClientEx(string host, int port) : base(host, port)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="SmtpClientEx"/> class
/// that sends e-mail by using the specified SMTP server.
/// </summary>
/// <param name="host">
/// A <see cref="String"/> that contains the name or
/// IP address of the host used for SMTP transactions.
/// </param>
public SmtpClientEx(string host) : base(host)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="SmtpClientEx"/> class
/// by using configuration file settings.
/// </summary>
public SmtpClientEx()
{
Initialize();
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the local host name used in SMTP transactions.
/// </summary>
/// <value>
/// The local host name used in SMTP transactions.
/// This should be the FQDN of the local machine.
/// </value>
/// <exception cref="ArgumentNullException">
/// The property is set to a value which is
/// <see langword="null"/> or <see cref="String.Empty"/>.
/// </exception>
public string LocalHostName
{
get
{
if (null == localHostName) return null;
return (string)localHostName.GetValue(this);
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentNullException("value");
}
if (null != localHostName)
{
localHostName.SetValue(this, value);
}
}
}
#endregion
#region Methods
/// <summary>
/// Returns the price "localHostName" field.
/// </summary>
/// <returns>
/// The <see cref="FieldInfo"/> for the private
/// "localHostName" field.
/// </returns>
private static FieldInfo GetLocalHostNameField()
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
return typeof(SmtpClient).GetField("localHostName", flags);
}
/// <summary>
/// Initializes the local host name to
/// the FQDN of the local machine.
/// </summary>
private void Initialize()
{
IPGlobalProperties ip = IPGlobalProperties.GetIPGlobalProperties();
if (!string.IsNullOrEmpty(ip.HostName) && !string.IsNullOrEmpty(ip.DomainName))
{
this.LocalHostName = ip.HostName + "." + ip.DomainName;
}
}
#endregion
}
}
smitra
Sundance Kid
Hi Durgaprasad.
I've been referring to RFC 821, 2821, and 1123. Indeed the FQDN or IP can be provided by HELO (or EHLO), but I can't find any reference about assuming the domain of the server if FQDN isn't supplied. I'd love to know if indeed that's true.
I added the requested section to the app.config file and but the resultant trace doesn't look much different to my eye. Here's the Sources section just to make sure it's right and the trace is further down.
<source name="System.Net.Sockets">
<listeners>
<add name="TraceLog"/>
</listeners>
</source>
<!-- This section defines the logging configuration for My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog"/>
<!-- Uncomment the below section to write to the Application Event Log -->
<!--<add name="EventLog"/>-->
</listeners>
</source>
</sources>
TRACE:
System.Net Information: 0 : [2560] Associating MailMessage#50934842 with Message#10366524
System.Net Verbose: 0 : [2560] SmtpClient::.ctor(host=192.168.0.1)
System.Net Information: 0 : [2560] Associating SmtpClient#63840421 with SmtpTransport#54246671
System.Net Verbose: 0 : [2560] Exiting SmtpClient::.ctor() -> SmtpClient#63840421
System.Net Verbose: 0 : [2560] SmtpClient#63840421::Send(MailMessage#50934842)
System.Net Information: 0 : [2560] SmtpClient#63840421::Send(DeliveryMethod=Network)
System.Net Information: 0 : [2560] Associating SmtpClient#63840421 with MailMessage#50934842
System.Net Information: 0 : [2560] Associating SmtpTransport#54246671 with SmtpConnection#25181126
System.Net Information: 0 : [2560] Associating SmtpConnection#25181126 with ServicePoint#59408853
System.Net Information: 0 : [2560] Associating SmtpConnection#25181126 with SmtpPooledStream#56152722
System.Net Error: 0 : [2560] Exception in the SmtpClient#63840421::Send - Command parameter not implemented. The server response was: <bo>: Helo command rejected: need fully-qualified hostname
System.Net Error: 0 : [2560] at System.Net.Mail.RecipientCommand.CheckResponse(SmtpStatusCode statusCode, String response)
at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
System.Net Error: 0 : [2560] Exception in the
#12036987::UnhandledExceptionHandler - Command parameter not implemented. The server response was: <bo>: Helo command rejected: need fully-qualified hostname
System.Net Error: 0 : [2560] at System.Net.Mail.RecipientCommand.CheckResponse(SmtpStatusCode statusCode, String response)
at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at MRRS_GUI.frmLogin.Button1_Click(Object sender, EventArgs e) in I:\srjc\sp2k6\vb6821\MRRS\MRRS_GUI\frmLogin.vb:line 78
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at MRRS_GUI.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
System.Net Verbose: 0 : [2560] Exiting SmtpClient#63840421::Send()
Buhmann
Sean,
Could you add the sockets level tacing to your config file
<source name="System.Net.Sockets">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
That way we could see what is going on the wire at the sockets level.
I read the RFC and it seems that we should send the FQDN or an IPAddress. I also read in some other RFC that if we don't send the FQDN the server must assume the domain name of the server itself. Let me do some more research.
Please let me know which RFC you are referring to.
Ahmad Ariff Baharudin
I'm in the same boat... trying to send mail directly to mx record for server instead of relaying through my mailserver. Works good except for FQDN and no backwards compat with HELO.
If anyone has suggestions or status info, I'm all ears :)
anton_tu
Weve encountered the same problem.
Tried:
* disabling the netbios via wins
* Placing entries into hosts file
Interestingly using another marketed .NET Email control namespace, it also does the same thing.... a point to note is that this Namespace is built on .net framework 1.1 not 2.0.
We are currently trying all sorts of DNS tricks to try and resolve this but given what I've learned from the posts above, Im begining to wonder if a solution even exists.
Under IIS smtp there is an option for supplying "Fully Qualified domain name". Why is such a setting unavailable for system.net.mail
Is this tool simply unintended for direct SMTP mailout Is the intended design usage (ideally) to specify a relay server
Example SMTP session of what goes wrong:
220 postoffice03.mail-hub.dodo.com.au service ready
EHLO DEV-TEMP
550-HELO/EHLO must contain a FQDN or IP literal
HELO DEV-TEMP
550 please see RFC 2821 section 4.1.1.1 Forcing disconnection from SMTP server.
QUIT
550-HELO/EHLO must contain a FQDN or IP literal Disconnected.
I'd really like to see some resolution to this. Its already having implications on our production environment applications.
Tintxo
Hi,
I have the same Problem....
Obviously there is no Solution in .NET 2.
Do you know if the SMTPClient is changed in .NET 3
Chris
Bradley Lane
I've logged a suggestion that this behavior should be changed:
http://lab.msdn.microsoft.com/ProductFeedback/viewfeedback.aspx feedbackid=d31e8d9e-9839-4c86-876b-ca5af1910091
DaManJ
Why would you need the FQDN of the sending host
Could you send me the system.net trace file for this
Look at http://blogs.msdn.com/dgorti for instructions on how to get a trace
GuySmiley
The FQDN from the sending host is used in the UCE controls of Postfix to ensure that the sending host can be found using a reverse DNS lookup. This is a strict enforcement of RFC 821 used by many SMTP servers to help reduce SPAM. The rationale is that if a domain specified in a HELO message cannot be found using rDNS, it probably doesn't exist and therefore is more likely to be used for some nefarious reason.
It would seem reasonable to have an option to enable the FQDN to be sent by the .Net SmtpClient.
By the way, your blog had an interesting comment about NetMon. However, when I tried to install it using the instructions you gave (on WinXP SP2) there was no NetMon option available to install.
Thanks for your help.
Here's the trace.
System.Net Information: 0 : [2424] Associating MailMessage#37535352 with Message#46630754
System.Net Verbose: 0 : [2424] SmtpClient::.ctor(host=192.168.0.1)
System.Net Information: 0 : [2424] Associating SmtpClient#47616313 with SmtpTransport#16973140
System.Net Verbose: 0 : [2424] Exiting SmtpClient::.ctor() -> SmtpClient#47616313
System.Net Verbose: 0 : [2424] SmtpClient#47616313::Send(MailMessage#37535352)
System.Net Information: 0 : [2424] SmtpClient#47616313::Send(DeliveryMethod=Network)
System.Net Information: 0 : [2424] Associating SmtpClient#47616313 with MailMessage#37535352
System.Net Information: 0 : [2424] Associating SmtpTransport#16973140 with SmtpConnection#24026409
System.Net Information: 0 : [2424] Associating SmtpConnection#24026409 with ServicePoint#16561909
System.Net Information: 0 : [2424] Associating SmtpConnection#24026409 with SmtpPooledStream#57566403
System.Net Error: 0 : [2424] Exception in the SmtpClient#47616313::Send - Command parameter not implemented. The server response was: <bo>: Helo command rejected: need fully-qualified hostname
System.Net Error: 0 : [2424] at System.Net.Mail.RecipientCommand.CheckResponse(SmtpStatusCode statusCode, String response)
at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
System.Net Error: 0 : [2424] Exception in the
#35320229::UnhandledExceptionHandler - Command parameter not implemented. The server response was: <bo>: Helo command rejected: need fully-qualified hostname
System.Net Error: 0 : [2424] at System.Net.Mail.RecipientCommand.CheckResponse(SmtpStatusCode statusCode, String response)
at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at MRRS_GUI.frmLogin.Button1_Click(Object sender, EventArgs e) in I:\srjc\sp2k6\vb6821\MRRS\MRRS_GUI\frmLogin.vb:line 79
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at MRRS_GUI.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
System.Net Verbose: 0 : [2424] Exiting SmtpClient#47616313::Send()