Microsoft MVP성태의 닷넷 이야기
.NET Framework: 761. C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법 [링크 복사], [링크+제목 복사],
조회: 23712
글쓴 사람
정성태 (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)
390정성태11/6/200626763    답변글 .NET Framework: 74.9. WCF에 SSL 적용 (2) - 서비스 제작파일 다운로드1
356정성태10/7/200622318COM 개체 관련: 19. COM의 Apartment를 이해해 보자. [8]
386light10/30/200617272    답변글 COM 개체 관련: 19.1. [답변]: COM 객체를 글로벌마샬으로 만든후, 사용한다.
355정성태10/9/200625012개발 환경 구성: 19. Internet_Zone 하위에 새로운 코드 그룹을 추가하는 예제 [4]파일 다운로드2
353정성태12/31/200633307개발 환경 구성: 18. 윈도우즈 인증서 서비스 이야기 [3]
354정성태10/23/200635896    답변글 개발 환경 구성: 18.1. 윈도우즈 인증서 서비스 설치
372정성태12/31/200637767    답변글 개발 환경 구성: 18.2. 웹 사이트에 SSL을 적용 [3]
373정성태10/24/200629139    답변글 개발 환경 구성: 18.3. 사용자 입장에서의 HTTPS 접근 (1)
374정성태10/25/200626401    답변글 개발 환경 구성: 18.4. 사용자 입장에서의 HTTPS 접근 (2)
391정성태11/7/200630552    답변글 개발 환경 구성: 18.5. 사용자 인증서 발급
392정성태11/11/200643799    답변글 개발 환경 구성: 18.6. 인증서 관리 (1) - 내보내기/가져오기
394정성태11/9/200628300    답변글 개발 환경 구성: 18.7. 인증서 관리 (2) - 개인키를 내보낼 수 있는 유형의 인증서 발급 [1]
395정성태11/9/200640398    답변글 개발 환경 구성: 18.8. 인증서 관리 (3) - 인증서 MMC 관리자 사용
414정성태12/23/200632107    답변글 개발 환경 구성: 18.9. CRL(Certificate Revocation List) 관리
428정성태12/31/200644999    답변글 개발 환경 구성: 18.10. IIS 7 - SSL 사이트 설정하는 방법 [4]
429정성태12/31/200630948    답변글 개발 환경 구성: 18.11. 서비스를 위한 인증서 설치
352정성태10/2/200620642개발 환경 구성: 17. VPC에 Linux 설치하는 방법 [1]
351정성태10/8/200623185개발 환경 구성: 16. 성태의 무식한(!) 리눅스 탐방기. [4]
349정성태9/26/200621962디버깅 기술: 10. C++/CLI에서 제공되는 명시적인 파괴자의 비밀
347정성태10/6/200625713디버깅 기술: 9. .NET IDisposable 처리 정리 [1]
346정성태9/23/200619248개발 환경 구성: 15. 툴박스에 컨트롤이 자동으로 나타나도록 해주는 옵션 설정
345정성태9/20/200618442오류 유형: 12. WCF 오류 메시지 - Error while trying to reflect on attribute 'MessageContractAttribute'
343정성태10/18/200630282개발 환경 구성: 14. SandCastle 사용법 (NDoc을 대체하는 문서화 도구) [1]파일 다운로드1
344정성태9/20/200620524    답변글 개발 환경 구성: 14.1. 오류 유형 - GAC 에 등록된 DLL 에 대한 문서화 시 오류
340정성태9/15/200619688개발 환경 구성: 13. ISO 파일을 가상 CD-ROM으로 매핑해주는 프로그램
339정성태9/14/200619192오류 유형: 11. ProtocolsSection?
... 181  182  183  [184]  185  186  187  188  189  190  191  192  193  194  195  ...