Azure 가상 머신(VM)에서 SMTP 메일 전송하는 방법
SMTP를 이용한 메일 전송 프로그램을 - 예를 들어 천리안, Outlook(Office365)과 Gmail의 경우 - 다음과 같이 작성할 수 있습니다.
using System.Net;
using System.Net.Mail;
class Program
{
static void Main(string[] args)
{
SmtpClient smtp = new SmtpClient();
SetProfile(smtp, SmtpProfile.Chollian);
MailAddress from = new MailAddress("from@test.com");
MailAddress to = new MailAddress("to@test.com");
MailMessage msg = new MailMessage(from, to);
msg.Body = "Test is good";
msg.Subject = "Test mail";
smtp.Send(msg);
}
private static void SetProfile(SmtpClient smtp, SmtpProfile profile)
{
switch (profile)
{
case SmtpProfile.Chollian:
smtp.Host = "mail.chol.com";
smtp.Port = 25;
smtp.EnableSsl = false;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.Credentials = new NetworkCredential("...", "...");
break;
case SmtpProfile.Gmail:
smtp.Host = "smtp.gmail.com";
// smtp.Port = 465;
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential("...", "...");
break;
case SmtpProfile.Office365:
smtp.Host = "smtp.office365.com";
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential("...", "...");
break;
}
}
}
public enum SmtpProfile
{
Chollian,
Gmail,
Office365,
}
이 프로그램을 Azure 가상 머신에서 천리안을 대상으로 실행하면 다음과 같은 오류가 발생합니다.
Unhandled Exception: System.Net.Mail.SmtpException: Failure sending mail. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 203.252.1.111:25
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.ServicePoint.GetConnection(PooledStream PooledStream, Object owner, Boolean async, IPAddress& address, Socket& abortSocket, Socket& abortSocket6)
at System.Net.PooledStream.Activate(Object owningObject, Boolean async, GeneralAsyncDelegate asyncCallback)
at System.Net.ConnectionPool.GetConnection(Object owningObject, GeneralAsyncDelegate asyncCallback, Int32 creationTimeout)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at ConsoleApp1.Program.Main(String[] args) in C:\temp\ConsoleApp1\ConsoleApp1\Program.cs:line 25
예전에 Azure에서 SMTP 사용 관련 글을 썼었는데,
Azure PaaS 웹 응용 프로그램 배포 후 SMTP 서버 구성
; https://www.sysnet.pe.kr/2/0/1443
덧글에 언급된 내용대로 Azure에서 SMTP 사용이 (Azure 구독 유형에 따라) 막혔습니다.
Troubleshoot outbound SMTP connectivity issues in Azure
; https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity
잘 보면, 막힌 것은 SMTP 25번 포트라고 하며 실제로 telnet 등으로 Azure VM으로부터 외부 서버에 25번 포트로 접속을 시도하면 실패하게 됩니다.
C:\temp> telnet mail.chol.com 25
Connecting To mail.chol.com...Could not open connection to the host, on port 25: Connect failed
따라서, Outlook과 Gmail처럼 587 포트로 바뀌게 되는 경우에는 정상적으로 사용할 수 있습니다. 참고로,
sendgrid 같은 외부 메일 서비스를 소개하는 글이 종종 눈에 띄는데, 한 달 무료로 사용할 수 있으므로 테스트 후 결제를 고려할 수 있습니다. ^^
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
기타, 오류 메시지 상황을 보면 계정 정보가 틀린 경우 다음과 같은 예외가 발생합니다.
Unhandled Exception: System.Net.Mail.SmtpFailedRecipientException: Mailbox unavailable. The server response was: 5.7.1 You(ip:221.155.83.250) are NOT allowed to RELAY (receiver:test@test.com).
at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, Boolean allowUnicode, SmtpFailedRecipientException& exception)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at ConsoleApp1.Program.Main(String[] args) in C:\temp\ConsoleApp1\ConsoleApp1\Program.cs:line 26
또는 Gmail 사용 시 다음과 같은 예외가 발생한다면?
Unhandled Exception: System.Net.Mail.SmtpException: Failure sending mail. ---> System.IO.IOException: Unable to read data from the transport connection: net_io_connectionclosed.
at System.Net.Mail.SmtpReplyReaderFactory.ProcessRead(Byte[] buffer, Int32 offset, Int32 read, Boolean readLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLines(SmtpReplyReader caller, Boolean oneLine)
at System.Net.Mail.SmtpReplyReaderFactory.ReadLine(SmtpReplyReader caller)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
설정한 포트를 확인해 465라면 587번으로 바꾸면 됩니다.
// smtp.Port = 465;
smtp.Port = 587;
또는, Outlook(Office365) 사용 시 다음과 같은 오류가 발생한다면?
Unhandled Exception: System.Web.HttpException: The message could not be sent to the SMTP server. The transport error code was 0x800ccc6c. The server response was 452 Check your E-mail Address
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: The message could not be sent to the SMTP server. The transport error code was 0x800ccc6c. The server response was 452 Check your E-mail Address
--- End of inner exception stack trace ---
at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at System.Web.Mail.SmtpMail.LateBoundAccessHelper.CallMethod(Object obj, String methodName, Object[] args)
--- End of inner exception stack trace ---
at System.Web.Mail.SmtpMail.LateBoundAccessHelper.CallMethod(Object obj, String methodName, Object[] args)
at System.Web.Mail.SmtpMail.CdoSysHelper.Send(MailMessage message)
at System.Web.Mail.SmtpMail.Send(MailMessage message)
at ConsoleApp2.Program.Main(String[] args) in C:\temp\ConsoleApp2\Program.cs:line 31
마이크로소프트 계정의 경우 보안이 엄격해서 전혀 다른 (IP 대역의) 장소에서 서비스를 사용하면 일단 차단을 하고 사용자 계정의 이메일로 허용 여부를 묻는 메일이 날아옵니다. 그 메일에서 명시적인 "허용"을 해야만 그 이후부터 Azure VM에서 정상적인 메일 전송을 할 수 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]