SmtpClient и проблема с отправкой почты

Столкнулся с проблемой отправки почты при помощи класса SmtpClient, входящего в состав .NET

Казалось бы, чего проще … пишем вот такой код:

  1: SmtpClient client = new SmtpClient("smtp.server.name");
  2:
  3: MailMessage message = new MailMessage(
  4:     "sender@domain.com",
  5:     "receiver@domain.com",
  6:     "Test message", "body content");
  7:
  8: client.Send(message);

Запускаем и получаем вот такую ошибку:

The message was rejected because of a forged HELO name – MyPCName

Происходит это из за того, что мой SMTP сервер в целях борьбы со спамом требует наличия корректного имени или адреса в команде HELO. Причем адрес с которого установлено соединение должен совпадать с адресом, указанным в команде. То есть сервер ожидает что то вроде “HELO client.domain.com” а вместо этого получает “HELO MyPCName” и не может определить адрес клиента. MyPCName – сетевое имя компьютера, который пытается отправить сообщение.

К сожалению, SmtpClient не поддерживает изменение имени домена отправителя, которое попадает в HELO. То есть стандартными методами проблему решить не удастся.

В сети не так много информации на эту тему. Описание проблемы найти можно, описание причины проблемы тоже. Но найти решение, работающее в .NET приложении оказалось не так просто. Внутри SmtpClient нужное нам значение хранится в одной из переменных класса. Однако эта переменная объявлена как private и напрямую изменить ее значение невозможно.

Вот по этой ссылке Richard Deeming предлагает свое решение, основанное на Reflection. Решение хорошее, но приведенный там код не может работать без изменений, так как в моем случае переменная в классе SmtpClient по какой то причине сменила свое название. После небольшой доработки мне все таки удалось добиться отправки сообщений через мой SMTP.

Модифицированный код теперь выглядит так:

  1: using System;
  2: using System.Net.Mail;
  3: using System.Net.NetworkInformation;
  4: using System.Reflection;
  5:
  6: namespace Trinet.Net.Mail
  7: {
  8:     /// <summary>
  9:     /// An extended <see cref="SmtpClient"/> which sends the
 10:     /// FQDN of the local machine in the EHLO/HELO command.
 11:     /// </summary>
 12:     public class SmtpClientEx : SmtpClient
 13:     {
 14:         #region Private Data
 15:
 16:         private static readonly FieldInfo localHostName = GetLocalHostNameField();
 17:
 18:         #endregion
 19:
 20:         #region Constructor
 21:
 22:         /// <summary>
 23:         /// Initializes a new instance of the <see cref="SmtpClientEx"/> class
 24:         /// that sends e-mail by using the specified SMTP server and port.
 25:         /// </summary>
 26:         /// <param name="host">
 27:         /// A <see cref="String"/> that contains the name or 
 28:         /// IP address of the host used for SMTP transactions.
 29:         /// </param>
 30:         /// <param name="port">
 31:         /// An <see cref="Int32"/> greater than zero that 
 32:         /// contains the port to be used on host.
 33:         /// </param>
 34:         /// <exception cref="ArgumentNullException">
 35:         /// <paramref name="port"/> cannot be less than zero.
 36:         /// </exception>
 37:         public SmtpClientEx(string host, int port) : base(host, port)
 38:         {
 39:             Initialize();
 40:         }
 41:
 42:         /// <summary>
 43:         /// Initializes a new instance of the <see cref="SmtpClientEx"/> class
 44:         /// that sends e-mail by using the specified SMTP server.
 45:         /// </summary>
 46:         /// <param name="host">
 47:         /// A <see cref="String"/> that contains the name or 
 48:         /// IP address of the host used for SMTP transactions.
 49:         /// </param>
 50:         public SmtpClientEx(string host) : base(host)
 51:         {
 52:             Initialize();
 53:         }
 54:
 55:         /// <summary>
 56:         /// Initializes a new instance of the <see cref="SmtpClientEx"/> class
 57:         /// by using configuration file settings.
 58:         /// </summary>
 59:         public SmtpClientEx()
 60:         {
 61:             Initialize();
 62:         }
 63:
 64:         #endregion
 65:
 66:         #region Properties
 67:
 68:         /// <summary>
 69:         /// Gets or sets the local host name used in SMTP transactions.
 70:         /// </summary>
 71:         /// <value>
 72:         /// The local host name used in SMTP transactions.
 73:         /// This should be the FQDN of the local machine.
 74:         /// </value>
 75:         /// <exception cref="ArgumentNullException">
 76:         /// The property is set to a value which is
 77:         /// <see langword="null"/> or <see cref="String.Empty"/>.
 78:         /// </exception>
 79:         public string LocalHostName
 80:         {
 81:             get
 82:             {
 83:                 if (null == localHostName) return null;
 84:                 return (string)localHostName.GetValue(this);
 85:             }
 86:             set
 87:             {
 88:                 if (string.IsNullOrEmpty(value))
 89:                 {
 90:                     throw new ArgumentNullException("value");
 91:                 }
 92:                 if (null != localHostName)
 93:                 {
 94:                     localHostName.SetValue(this, value);
 95:                 }
 96:             }
 97:         }
 98:
 99:         #endregion
100:
101:         #region Methods
102:
103:         /// <summary>
104:         /// Returns the price "localHostName" field.
105:         /// </summary>
106:         /// <returns>
107:         /// The <see cref="FieldInfo"/> for the private
108:         /// "localHostName" field.
109:         /// </returns>
110:         private static FieldInfo GetLocalHostNameField()
111:         {
112:             BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
113:             return typeof(SmtpClient).GetField("clientDomain", flags);
114:         }
115:
116:         /// <summary>
117:         /// Initializes the local host name to 
118:         /// the FQDN of the local machine.
119:         /// </summary>
120:         private void Initialize()
121:         {
122:             IPGlobalProperties ip = IPGlobalProperties.GetIPGlobalProperties();
123:             if (!string.IsNullOrEmpty(ip.HostName) && !string.IsNullOrEmpty(ip.DomainName))
124:             {
125:                 this.LocalHostName = ip.HostName + "." + ip.DomainName;
126:             }
127:         }
128:
129:         #endregion
130:     }
131: }

Код отправки почты также немного изменился:

  1: SmtpClientEx client = new SmtpClientEx("smtp.server.name");
  2:  client.LocalHostName = "client.domain.com";
  3: MailMessage message = new MailMessage(
  4:     "sender@domain.com",
  5:     "receiver@domain.com",
  6:     "Test message", "body content");
  7:
  8: client.Send(message);

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *