Microsoft MVP성태의 닷넷 이야기
.NET Framework: 761. C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법 [링크 복사], [링크+제목 복사],
조회: 15084
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

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
정성태

... 46  47  [48]  49  50  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12437정성태12/1/20209798VS.NET IDE: 155. pfx의 암호 키 파일을 Visual Studio 없이 등록하는 방법
12436정성태12/1/202010089오류 유형: 687. .NET Core 2.2 빌드 - error MSB4018: The "RazorTagHelper" task failed unexpectedly.
12435정성태12/1/202015565Windows: 181. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 (4) - ReuseUnicastPort를 이용한 포트 고갈 문제 해결 [1]파일 다운로드1
12434정성태11/30/202010889Windows: 180. C# - dynamicport 값의 범위를 알아내는 방법
12433정성태11/29/20209949Windows: 179. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 (3) - SO_PORT_SCALABILITY파일 다운로드1
12432정성태11/29/202011300Windows: 178. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 (2) - SO_REUSEADDR [1]파일 다운로드1
12431정성태11/27/20209219.NET Framework: 976. UnmanagedCallersOnly + C# 9.0 함수 포인터 사용 시 x86 빌드에서 오동작하는 문제파일 다운로드1
12430정성태11/27/20209940오류 유형: 686. Ubuntu - E: The repository 'cdrom://...' does not have a Release file.
12429정성태11/25/202010057디버깅 기술: 175. windbg - 특정 Win32 API에서 BP가 안 걸리는 경우
12428정성태11/25/20208983VS.NET IDE: 154. Visual Studio - .NET Core App 실행 시 dotnet.exe 실행 화면만 나오는 문제
12427정성태11/24/202010128.NET Framework: 975. .NET Core를 직접 호스팅해 (runtimeconfig.json 없이) EXE만 배포해 실행파일 다운로드1
12426정성태11/24/20208720오류 유형: 685. WinDbg Preview - error InitTypeRead
12425정성태11/24/20209802VC++: 141. Visual C++ - "Treat Warnings As Errors" 옵션이 꺼져 있는데도 일부 경고가 에러 처리되는 경우
12424정성태11/24/202010211VC++: 140. C++의 연산자 동의어(operator synonyms), 대체 토큰 [1]
12423정성태11/22/202011115.NET Framework: 974. C# 9.0 - (16) 제약 조건이 없는 형식 매개변수 주석(Unconstrained type parameter annotations)파일 다운로드1
12422정성태11/21/20208914.NET Framework: 973. .NET 5, .NET Framework에서만 허용하는 UnmanagedCallersOnly 사용예파일 다운로드1
12421정성태11/19/20208671.NET Framework: 972. DNNE가 출력한 NE DLL을 직접 생성하는 방법파일 다운로드1
12420정성태11/19/20207829오류 유형: 684. Visual C++ - MSIL .netmodule or module compiled with /GL found; restarting link with /LTCG; add /LTCG to the link command line to improve linker performance
12419정성태11/19/20209062VC++: 139. Visual C++ - .NET Core의 nethost.lib와 정적 링크파일 다운로드1
12418정성태11/19/202011139오류 유형: 683. Visual C++ - error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MDd_DynamicDebug'파일 다운로드1
12417정성태11/19/20208543오류 유형: 682. Visual C++ - warning LNK4099: PDB '...pdb' was not found with '...lib(pch.obj)' or at '...pdb'; linking object as if no debug info
12416정성태11/19/20209812오류 유형: 681. Visual C++ - error LNK2001: unresolved external symbol _CrtDbgReport
12415정성태11/18/20209876.NET Framework: 971. UnmanagedCallersOnly 특성과 DNNE 사용파일 다운로드1
12414정성태11/18/202010931VC++: 138. x64 빌드에서 extern "C"가 아닌 경우 ___cdecl name mangling 적용 [4]파일 다운로드1
12413정성태11/17/202010638.NET Framework: 970. .NET 5 / .NET Core - UnmanagedCallersOnly 특성을 사용한 함수 내보내기파일 다운로드1
12412정성태11/16/202012880.NET Framework: 969. .NET Framework 및 .NET 5 - UnmanagedCallersOnly 특성 사용파일 다운로드1
... 46  47  [48]  49  50  51  52  53  54  55  56  57  58  59  60  ...