Microsoft MVP성태의 닷넷 이야기
.NET Framework: 761. C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법 [링크 복사], [링크+제목 복사],
조회: 23707
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 7개 있습니다.)
기타: 58. Outlook에 설정한 SMTP/POP3(예:천리안 메일) 계정 암호를 잊어버린 경우
; https://www.sysnet.pe.kr/2/0/11010

기타: 59. outlook.live.com 메일 서비스의 아웃룩 POP3 설정하는 방법
; https://www.sysnet.pe.kr/2/0/11011

.NET Framework: 761. C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법
; https://www.sysnet.pe.kr/2/0/11537

개발 환경 구성: 454. Azure 가상 머신(VM)에서 SMTP 메일 전송하는 방법
; https://www.sysnet.pe.kr/2/0/11994

.NET Framework: 848. C# - smtp.daum.net 서비스(Implicit SSL)를 이용해 메일 보내는 방법
; https://www.sysnet.pe.kr/2/0/11995

오류 유형: 757. 구글 메일 - 아웃룩에서 메일 전송 시 Sending' reported error (0x800CCC0F, 0x800CCC92)
; https://www.sysnet.pe.kr/2/0/12784

닷넷: 2328. C# - MailKit: SMTP, POP3, IMAP 지원 라이브러리
; https://www.sysnet.pe.kr/2/0/13908




C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법

SMTP 서버에 아래와 같이 TLS를 설정한 경우,

cert_smtp_1.png
(Require TLS encryption)

SmtpClient를 이용해 다음과 같이 코딩을 할 수 있습니다.

SmtpClient smtp = new SmtpClient();
smtp.Host = "...[hostname]...";
smtp.EnableSsl = true;

MailAddress from = new MailAddress("test1@test.com");
MailAddress to = new MailAddress("test2@test.com");

MailMessage msg = new MailMessage(from, to);
msg.Body = "Test is good";
msg.Subject = "Test mail";

smtp.Send(msg);

그런데, Send에서 인증서 관련한 여러 가지 예외가 발생할 수 있습니다. 이럴 때는 ServerCertificateValidationCallback을 등록해 두면,

static void Main(string[] args)
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback += callBackFunc;

    SmtpClient smtp = new SmtpClient();
    
    ...[생략]...

    smtp.Send(msg);
}

static bool callBackFunc(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return false;
}

상황에 따른 오류를 sslPolicyErrors를 통해 알아낼 수 있습니다.

가령, SMTP 서버의 인증서에 등록된 Subject가 "smtpsvc.test.com"인데 다음과 같이 Host 이름을 주면,

smtp.Host = "192.168.100.5";  // "smtpsvc.test.com"가 아닌 다름 이름을 준 경우.

sslPolicyErrors 매개 변수는 System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch 값으로 그 사실을 알려주면서 Send 메서드에서는 다음과 같은 예외가 발생합니다.

Unhandled Exception: System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
...[생략]...
   at System.Net.Mail.ReadLinesCommand.Send(SmtpConnection conn)
   at System.Net.Mail.EHelloCommand.Send(SmtpConnection conn, String domain)
   at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
   at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
   at System.Net.Mail.SmtpClient.GetConnection()
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at ConsoleApp1.Program.Main(String[] args) in E:\ConsoleApp1\ConsoleApp1\Program.cs:line 34

또는 정상적으로 Host 명을 주었는데, 여전히 System.Security.Authentication.AuthenticationException 예외가 발생하면서 sslPolicyErrors == System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors 오류 값이 나올 수 있습니다. 이럴 때는 해당 인증서의 chain에 등록된 상위 인증서들을 클라이언트에서 신뢰할 수 없기 때문입니다. 대개의 경우 자체 인증서 서비스를 설치해서 운영하는 경우 저런 상황이 발생합니다. 따라서 SMTP SSL/TLS에 사용 중인 인증서를 발급한 자체 인증서 서비스의 (공개키만 보유한) 루트 인증서를 C# 클라이언트 프로그램이 실행되는 컴퓨터에 등록해 줘야 합니다.

또는, 상위 기관 없이 자체 발급한 인증서를 사용한다면 해당 (공개키만 보유한) 인증서만 동일하게 클라이언트에 등록해 주면 됩니다.




물론, 테스트를 위한 경우라면 인증서의 유효성 검사를 ServerCertificateValidationCallback을 이용해 무시할 수 있습니다. 즉, 다음과 같이 무조건 true를 반환하도록 만들면 됩니다.

static bool callBackFunc(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true;
}

ServerCertificateValidationCallback은 과거에도 WCF SSL 통신 관련해서 사용한 적이 있었습니다. ^^

basicHttpBinding + 사용자 정의 인증 구현
; https://www.sysnet.pe.kr/2/0/1082




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/8/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2018-07-13 01시39분
[황윤하] 안녕하세요 궁금한점이 있어 댓글 남깁니다.
위와 같이 인증 콜백 부분에서 콜백값이 RemoteCertificateNameMismatch , RemoteCertificateChainErrors 두개가 나타납니다.
특정 회사에서 테스트 시
[guest]
2018-07-13 01시42분
[황윤하] 아.. 댓글이 이상하게 남겨졌네요.. 이어서
특정 회사에서 테스트 시에만 저렇게 두개가 남겨지는데 이유를 잘 모르겠습니다.
인증 프로세스 콜백값을 임의로 true로 할수는 없습니다. (인증프로세스가 꼭 포함되어야 한다고 했습니다.)
저런 에러가 나는 이유가 무엇일까요?
그 특정회사는 Exchange를 사용하고 있으며 회사내에서 사용하는 메일 프로그램이 따로 있습니다.
피씨내에 아웃룩을 깔고 회사내 메일 프로그램에 전송 시 메일은 전송이 되는데 제가 개발한 프로그램에서는 전송이 되지 않습니다.
제가 개발한 프로그램에서 인증하는 과정에서 문제가 생긴 듯 한데.. 잘 모르겠습니다....ㅜㅜ
[guest]
2018-07-13 02시04분
저렇게 한다고 해서 "인증 프로세스"가 없어지는 것은 아닙니다. 인증은 그 나름대로 진행되지만, 단지 저 콜백은 "인증서의 유효성"만 체크하는 것을 생략할 수 있는 것입니다.

두 개의 메시지에 대한 오류 원인은 본문에 설명해 놓았습니다. 자세히 읽어보세요.
정성태
2018-07-13 02시09분
[황윤하] 아!! 네!! 인증 프로세스가 없어지는게 아닌거군요.. return을 true로 해서 다시 테스트 해보겠습니다! 좋은정보 정말 감사합니다!!!!!
[guest]
2021-03-26 09시22분
jstedfast/MailKit - cross-platform mail client library built on top of MimeKit.
; https://github.com/jstedfast/MailKit
정성태

... 181  182  183  184  185  186  187  188  [189]  190  191  192  193  194  195  ...
NoWriterDateCnt.TitleFile(s)
226정성태4/13/200615335Team Foundation Server: 1. TFS 오류 유형 - TF50608: Unable to retrieve information for security object
225정성태10/17/200614887.NET Framework: 67. VS.NET 2005 도구 상자에 있는 Workflow Activity 항목의 아이콘 변경
223정성태4/13/200626158.NET Framework: 66. Microsoft .NET Framework 2.0 Configuration 수동 설치파일 다운로드1
224정성태4/13/200619709    답변글 .NET Framework: 66.1. "Microsoft .NET Framework 2.0 Configuration" MSI 설치 파일 버전파일 다운로드1
222정성태4/13/200618707.NET Framework: 65. VS.NET 2005: 파일 기반 웹 프로젝트의 "Virtual Path" 제거
220정성태4/13/200616423.NET Framework: 64. ClickOnce - 배포 시 오류 : "Error: An unexpected error occurred -- The parameter is incorrect."
219정성태4/13/200631238.NET Framework: 63. ClickOnce - 최초 실행 시 보안 경고창 없애는 방법 [1]
216정성태4/13/200618297스크립트: 8. 3월 1일 ActiveX Patch 적용 후, JS 로 수정한 임베딩 컨트롤이 여전히 비활성화 되는 문제 [2]
215정성태4/13/200619638.NET Framework: 62. ASP.NET 웹 컨트롤 렌더링 가로채기
214정성태4/13/200618980.NET Framework: 61. DateTime - DateTime = 사이의 "Month" 수 계산 [2]
213정성태4/13/200621246.NET Framework: 60. localhost 이외의 컴퓨터에서 asmx 테스트 페이지 호출 [1]
218정성태4/13/200619605    답변글 .NET Framework: 60.1. asmx 테스트 페이지를 보여주고 싶지 않을 때
211정성태4/13/200617484VS.NET IDE: 38. VS.NET 2005 - "Export Template" 메뉴
210정성태4/13/200616963.NET Framework: 59. EXE 참조 가능 - VS.NET 2005 [2]
209정성태4/13/200616474스크립트: 7. 4월 12일 ActiveX 패치 문제를 해결할 수 있는 가장 간단한 방법 [6]파일 다운로드1
208정성태10/21/200616203Windows: 1. 성태도 ^^ Vista 설치 해봤습니다.
212정성태10/20/200615726    답변글 Windows: 1.1. Vista 에서 WinFX 런타임 구동
207정성태4/13/200624698VC++: 23. VC++ RGS 파일에 사용자 정의 파라미터 추가
205정성태4/13/200621764VS.NET IDE: 37. devenv.exe를 이용한 Command Line 컴파일 [1]
204정성태5/8/200616992웹: 2. Server Unavailable - Server Application Unavailable
203정성태4/13/200615845웹: 1. IIS 설정 옵션: Verify(Check) that file exists
202정성태4/13/200615562VS.NET IDE: 36. Automatically synchronize with an Internet time server
201정성태4/13/200618581기타: 12. XMLHTTP Failure and SUS Admin
200정성태4/13/200617969.NET Framework: 58. 웹 서비스 메서드 호출 오류 유형 - text/html; charset=xxx, but expected 'text/xml'
199정성태4/13/200619332스크립트: 6. XHTML or HTML 4.01 표준 준수
194정성태4/13/200618617VC++: 22. IDL Library 절
... 181  182  183  184  185  186  187  188  [189]  190  191  192  193  194  195  ...