Ubuntu 16.04下.NET Core调用OVH SMTP发邮件报Base64格式错误求助
问题描述
我在运行Ubuntu 16.04的测试服务器上,使用OVH专业账户的pro1.mail.ovh.net SMTP发送邮件时出现Base64格式错误,但在Windows 10工作站调试时可正常发送。我确认密码是正确的,已经排查过密码相关的类似问题,但仍未解决。
代码实现
var smtp = m_emailConfiguration["Smtp"]; var email = m_emailConfiguration["Email"]; var password = m_emailConfiguration["Password"]; try { using (var smtpClient = new SmtpClient(smtp, 587)) { var mailMessage = new MailMessage(email, mailTo, subject, body); smtpClient.UseDefaultCredentials = false; smtpClient.Credentials = new NetworkCredential(email, password); smtpClient.EnableSsl = true; smtpClient.Send(mailMessage); } } catch (Exception ex) { throw new Exception(ex.InnerException.Message); }
报错信息
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters
完整堆栈跟踪
Exception: System.Net.Mail.SmtpException: Failure sending mail. ---> System.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. at System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) at System.Convert.FromBase64String(String s) at System.Net.Mail.SmtpNegotiateAuthenticationModule.GetSecurityLayerOutgoingBlob(String challenge, NTAuthentication clientContext) at System.Net.Mail.SmtpNegotiateAuthenticationModule.Authenticate(String challenge, NetworkCredential credential, Object sessionCookie, String spn, ChannelBinding channelBindingToken) at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port) at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port) at System.Net.Mail.SmtpClient.GetConnection() at System.Net.Mail.SmtpClient.Send(MailMessage message)
解决思路
从报错堆栈来看,问题出在**Negotiate认证模块(Kerberos/NTLM)**的Base64解析上,这是跨平台环境下常见的SMTP认证兼容性问题——Windows上默认的认证逻辑和Linux(Ubuntu)上的实现存在差异,导致Linux端尝试用Negotiate认证时解析失败,而Windows端能自动 fallback 到正确的LOGIN认证方式。
1. 强制指定SMTP认证方式为LOGIN
在Linux环境下,SmtpClient可能会优先尝试Negotiate认证(而非LOGIN),但OVH的SMTP服务器大概率只支持LOGIN认证。你可以手动指定认证机制:
如果是使用Mono(Ubuntu 16.04上常见的.NET运行时),可以添加以下代码:
smtpClient.AuthenticationMechanisms = "LOGIN";
完整修改后的代码:
var smtp = m_emailConfiguration["Smtp"]; var email = m_emailConfiguration["Email"]; var password = m_emailConfiguration["Password"]; try { using (var smtpClient = new SmtpClient(smtp, 587)) { var mailMessage = new MailMessage(email, mailTo, subject, body); smtpClient.UseDefaultCredentials = false; smtpClient.Credentials = new NetworkCredential(email, password); smtpClient.EnableSsl = true; // 强制使用LOGIN认证 smtpClient.AuthenticationMechanisms = "LOGIN"; smtpClient.Send(mailMessage); } } catch (Exception ex) { throw new Exception(ex.InnerException.Message); }
2. 检查配置文件的密码读取编码/转义问题
虽然你确认密码正确,但Ubuntu环境下读取配置文件时,可能存在编码差异或特殊字符转义问题:
- 检查配置文件中密码是否包含空格、换行符或不可见字符(比如Windows下的
\r\n和Linux下的\n差异) - 尝试直接硬编码密码进行测试(仅用于排查,不要在生产环境这么做),确认是否是配置读取环节的问题
3. 替换为跨平台兼容性更好的MailKit库
System.Net.Mail.SmtpClient已经被标记为过时,且跨平台支持有限。推荐使用MailKit(专门为跨平台设计的邮件库),它能更灵活地处理SMTP认证:
首先安装MailKit包:
dotnet add package MailKit
然后替换代码为:
using MailKit.Net.Smtp; using MimeKit; var smtp = m_emailConfiguration["Smtp"]; var email = m_emailConfiguration["Email"]; var password = m_emailConfiguration["Password"]; try { var message = new MimeMessage(); message.From.Add(new MailboxAddress("Sender Name", email)); message.To.Add(new MailboxAddress("Recipient Name", mailTo)); message.Subject = subject; message.Body = new TextPart("plain") { Text = body }; using (var client = new SmtpClient()) { client.Connect(smtp, 587, true); client.Authenticate(email, password); client.Send(message); client.Disconnect(true); } } catch (Exception ex) { throw new Exception(ex.Message); }
MailKit会自动适配服务器支持的认证方式,避免Linux下的Negotiate认证问题,同时提供更清晰的错误信息。
内容的提问来源于stack exchange,提问作者andy200486

