Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticating with a non-compliant SMTP server

I'm supposed to send an e-mail through a SMTP server. This SMTP server requires authentication. However, if I use the default authentication mechanism of the .NET SmtpClient, authentication fails with 504 Unrecognized Authentication Type.

When using PuTTy I'm able to successfully authenticate:

250 AUTH LOGIN PLAIN
AUTH LOGIN
334 VXNlcm5hbWU6
Some base64 encoded username
334 UGFzc3dvcmQ6
Some base64 encoded password
235 Authentication Successful

The SmtpClient is using a slightly different approach, where the username is passed in with the AUTH LOGIN command:

250 AUTH LOGIN PLAIN
AUTH LOGIN Some base64 encoded username
504 Unrecognized Authentication
MAIL FROM: ...

It seems to be ignoring the 504, because it is sending the MAIL FROM command. Reading some sources on the internet, it is allowed to send the username with the AUTH LOGIN command:

However, there exists a different, RFC compliant version of this behavior, where the client initially sends the userid already with the AUTH LOGIN method

The problem is most likely at the SMTP server's side, but I have no control over it.

Is it possible to make SmtpClient send the commands separately?


Sample code

using (var client = new SmtpClient(_configuration.Host, _configuration.Port))
{
    client.UseDefaultCredentials = false;
    client.ServicePoint.MaxIdleTime = 1;
    client.EnableSsl = false;
    client.Credentials = new NetworkCredential(_configuration.Username, _configuration.Password, _configuration.Domain);

    var from = new MailAddress(string.Format("{0}@{1}", _configuration.Sender, _configuration.Domain));
    var to = new MailAddress(string.Format("{0}@{1}", to, _configuration.Domain));

    var message = new MailMessage(from, to)
    {
        Body = body
    };

    client.Send(message);
}

DIY

Just for fun (and not production) I've tried to do my own communication:

using (var connection = new TcpClient(_configuration.Host, _configuration.Port))
using (NetworkStream stream = connection.GetStream())
{
    string header = Read(stream);
    Reply(stream, "EHLO " + Environment.MachineName);

    while (!Read(stream).ToUpperInvariant().Contains("AUTH LOGIN PLAIN"))
    {
    }
    Reply(stream, "AUTH LOGIN");

    string requestUsername = Read(stream);
    Reply(stream, Convert.ToBase64String(Encoding.ASCII.GetBytes(_configuration.Username)));

    string requestPassword = Read(stream);
    Reply(stream, Convert.ToBase64String(Encoding.ASCII.GetBytes(_configuration.Password)));
    string authSucces = Read(stream);

    Reply(stream, string.Format("MAIL FROM: <{0}@{1}>", _configuration.Sender, _configuration.Domain));
    string senderOk = Read(stream);

    Reply(stream, string.Format("RCPT TO: <{0}@{1}>", to, _configuration.Domain));
    string rcptOk = Read(stream);

    Reply(stream, "DATA");
    string sendData = Read(stream);

    Reply(stream, body);
    Reply(stream, string.Empty);
    Reply(stream, ".");
    Reply(stream, string.Empty);

    stream.Close();
    connection.Close();
}

private string Read(NetworkStream stream)
{
    var data = new byte[1024];
    int received = stream.Read(data, 0, data.Length);
    string contents = Encoding.ASCII.GetString(data, 0, received);

    return contents;
}

private void Reply(NetworkStream stream, string reply)
{
    reply = reply + Environment.NewLine;
    stream.Write(Encoding.ASCII.GetBytes(reply), 0, reply.Length);
    stream.Flush();
}

This works great. So it is definitely about how the SmtpClient and the actual Smtp Server communicate.


Work-around

It turns out we have been communicating with a system that implemented the SMTP protocol all by itself and they did it wrong. So we have decided to do the communication ourselves, until the vendor has fixed their code. Luckily it is only for internal purposes and the communication is very predictable. We are using the DIY-code with some refactoring and cleanup.

like image 291
Jeroen Avatar asked Nov 09 '22 03:11

Jeroen


1 Answers

I had the same problem Here is my solution/workaround: sending email using System.Web.Mail instead of System.Net.Mail. I know this is not the best possible solution because the library is deprecated but it may help until the vendor fixes the code.

System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage();
    msg.Body = message.Body;

    string smtpServer = "mail.business.it";
    string userName = "username";
    string password = "password";
    int cdoBasic = 1;
    int cdoSendUsingPort = 2;
    if (userName.Length > 0)
    {
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserver", smtpServer);
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", 25);
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusing", cdoSendUsingPort);
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", cdoBasic);
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", userName);
        msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", password);
    }
    msg.To = message.Destination;
    msg.From = "[email protected]";
    msg.Subject = message.Subject;
    msg.BodyFormat = MailFormat.Html;//System.Text.Encoding.UTF8;
    SmtpMail.SmtpServer = smtpServer;
    SmtpMail.Send(msg);
like image 163
silviagreen Avatar answered Nov 14 '22 23:11

silviagreen