메일서버 - 시작하기
이전에 메일이 동작하는 거에 대해 설명을 했다. 메일서버를 구축하기전에 메일이라는 게 어떻게 작동하는지 알아야 메일서버를 구축하는데 수월하다. 메일을 이용하는 방법은 다양하다. 1. 기
veno.tistory.com
앞 게시글에 이어서 글을 작성해보려고 한다.
이전에는 그냥 JAMES를 설치하고 어떤 알찬 구성품이 있는지 한번 핥아보았다.
이번글에서는 이 JAMES를 작동시키기 위해 어떤 노력과 지랄 옘병을 떨어야 얘가 작동하는지 해볼 것이다.
참고로 이 JAMES는 실제로 구동하는 메일 서버이고 상용화도 가능하기 때문에 각종 보안에 유의해야 한다.
메일이 해킹이 당할 수도 있고 메일 서버 또한 해킹당할 수도 있기 때문에 리눅스 보안에 엄청 신경 써야 한다. 그래도 어느 정도 네트워크와 시스템에 대한 기본지식이 다져있어야 하며, 해킹에 대해 어느정도 알고 있으면 더 좋다.
Java open JDK 설치
JAMES는 자바기반 작동하는 방식이기 때문에 자바언어가 필요하다.
하지만 리눅스는 자바가 기본으로 설치되어 있을 수도 있으니 이 부분은 따로 확인해봐야 한다.
아파치에서는 JDK11 버전에서 정상적으로 작동이 되었다는 걸 공식문서로 작성했다.
그럼 우리는 JDK11 버전 이상을 설치하면 좋지만, 자바 회사가 JDK11에 있던 기능을 상위버전에서는 삭제하는 일이 있을 수 있다. 그냥 미연의 사건을 방지하기 위해 우리도 JDK11 버전을 설치하면 된다.
sudo apt-get install openjdk-11-jdk -y
패키지 관리자로 설치를 진행하는 거라 우리가 따로 설정해야 하는 부분은 그냥 환경변수 밖에 없다.
환경변수란?
우리가 어떠한 프로그램(+언어)이나 소프트웨어를 설치하면 설치한 경로로 꼭 들어가서 실행해야만 작동이 된다.
하지만 매번 그 경로로 들어가서 작업하기에는 큰 어려움이 있다. 자바언어를 사용하는 프로그램 같은 경우는 그 프로그램을 아예 뜯어서 소스코드를 수정해야 하는 더러운 일이 있다. 하지만 환경변수를 이용하면 경로를 넣어줄 필요가 없고, 시스템 어디서나 접근이 가능하게끔 시스템이 알아서 해당 경로로 이동시켜 작동하게 해 준다.
윈도우는 GUI가 국룰이라 큰 어려움이 없지만 리눅스는 CLI가 국룰이다.
때문에 리눅스에서도 환경변수를 사용하려면 당연히 명령어로 입력해야 한다.
sudo vim ~/.bashrc
sudo : 관리자 권한
vim : 텍스트 편집기
~/ : 사용자 루트 경로(사용자 홈 메인 경로)
.bashrc : 환경변수를 수정할 수 있는 파일
여기서 환경변수를 추가해 주면 된다.
실행하면 이상한 코드들이 있을 거다. 여기서 아무것도 만지지 말고 맨 아래로 내리면 "fi"로 끝나는 글자가 있을 건데 그 아래에 새 문구를 추가하면 된다.
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$PATH:$JAVA_HOME/bin
JAVA_HOME이라는 변수에 경로 /usr/lib/jvm/java-11-openjdk-amd64를 추가했지.
당연히 이 경로는 우리가 위에 설치했던 자바 JDK11 버전의 메인 경로이다.
PATH라는 변수에는 기존 PATH에 새로운 경로를 추가하는 거다.
$는 기존에 있는 변수를 사용하는 걸 뜻하는 것이기 때문에 자바 메인 경로인 $JAVA_HOME이라고 지정했고 거기에 bin디렉터리를 추가했다. :는 프로그래밍 언어에서의 ;과 같은 개념이다.
이렇게 하고 esc키를 눌러 :wq를 하면 저장 후 나가기가 된다.
source ~/.bashrc
새롭게 편집된. bashrc를 업데이트하여 편집한 부분을 갱신시켜 준다.
그 후 명령어 java -version이라고 치면 자바 버전이 나올 거다. 그러면 환경변수는 잘 적용된 거다.
이러면 JAMES는 지금 즉시 가동해도 문제없이 가동이 될 것이다. 하지만 그전에 해야 할 노가다가 뒤지게 많다.
지금부터 지옥문 OPEN이니 눈깔 잘 뜨고 따라 하면 된다.
DNS설정
DNS는 Domain Name Service의 약어로 도메인명을 IP주소로 바꿔주거나 IP주소를 도메인명으로 바꿔준다.
컴퓨터는 인터넷을 연결하기 위해 IP주소가 필요하다.
무조건이다. 그 이외는 연결이 안 된다.
우리가 구글에 검색을 하고 싶으면 제일 먼저 하는 것이 주소창에 google.com이다.
사실 이거는 인터넷세상에서 씨알도 안 먹히는 방법이다. 무조건 아이피 주소를 입력해야 한다.
하지만 사람은 사람의 두뇌로 아이피 주소를 하나하나 다 기억할 수 없다는 걸 알고 있다. 참으로 슬픈 현실이지만 팩트이다.
그래서 기가맥히게 생각한 서비스가 DNS이다.
이는 142.250.204.78라는 주소를 가진 주소를 사람들이 쉽게 기억하고 쉽게 접근 가능하게 해 준 서비스이다.
우리가 만약 142.250.204.78이라는 아이피 주소를 입력하면 DNS가 이를 보고 142.250.204.78→google.com이라고 변환시켜 준다. 이러면 우리의 인터넷 삶은 더 나아지게 해 주는 거다.
그럼 메일 서버에서 이를 설정해줘야 한다.
<dnsservice>
<servers>
<!--Enter ip address of your DNS server, one IP address per server -->
<!-- element. -->
<server>168.126.63.1</server>
</servers>
<!-- Change autodiscover to false if you would like to turn off autodiscovery -->
<!-- and set the DNS servers manually in the<servers>section -->
<autodiscover>false</autodiscover>
<authoritative>false</authoritative>
<!-- Maximum number of entries to maintain in the DNS cache -->
<maxcachesize>50000</maxcachesize>
여기서 DNS주소는 당연히 우리가 쓰는 서버에 할당된 DNS서버 주소를 쑤셔 넣어야 한다.
나는 가비아에서 서버를 사용하기 때문에 가비아 서버에 할당된 DNS주소를 넣었다.
확인하는 방법은 /etc/resolv.conf 경로에 있는 파일을 훑어보면 된다. 당연히 가비아의 우분투 기준이니 참고할 것,
도메인 설정하기
도메인은 당연히 우리가 메일을 보내려고 하면 필요하다.
나는 무려 2년에 2만 2천 원을 냈던 내 도메인을 넣을 거다. 이거는 은근 설정이 쉽다.
<domainlist class="org.apache.james.domainlist.jpa.JPADomainList">
<autodetect>false</autodetect>
<autodetectIP>false</autodetectIP>
<defaultDomain>veno.kr</defaultDomain>
</domainlist>
그냥 defaultDomain에 내 도메인을 넣으면 된다. ¯\_(ツ)_/¯
SMTP 설정하기
<?xml version="1.0"?>
<smtpservers>
<smtpserver enabled="true">
<jmxName>smtpserver</jmxName>
<bind>0.0.0.0:25</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="false" startTLS="false">
<keystore>file://conf/인증서.jks</keystore>
<keystoreType>JKS</keystoreType>
<secret>인증서 비밀번호</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectiontimeout>360</connectiontimeout>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<auth>
<announce>always</announce>
<requireSSL>true</requireSSL>
<plainAuthEnabled>true</plainAuthEnabled>
</auth>
<authorizedAddresses>127.0.0.0/8</authorizedAddresses>
<maxmessagesize>0</maxmessagesize>
<addressBracketsEnforcement>true</addressBracketsEnforcement>
<handlerchain>
<handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
<handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
</handlerchain>
</smtpserver>
<smtpserver enabled="true">
<jmxName>smtpserverstartTLS</jmxName>
<bind>0.0.0.0:587</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="false" startTLS="true">
<keystore>file://conf/인증서.jks</keystore>
<keystoreType>JKS</keystoreType>
<secret>인증서 비밀번호</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectiontimeout>360</connectiontimeout>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<auth>
<announce>always</announce>
<requireSSL>true</requireSSL>
<plainAuthEnabled>true</plainAuthEnabled>
</auth>
<authorizedAddresses>127.0.0.0/8</authorizedAddresses>
<maxmessagesize>0</maxmessagesize>
<addressBracketsEnforcement>true</addressBracketsEnforcement>
<handlerchain>
<handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
<handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
</handlerchain>
</smtpserver>
<smtpserver enabled="true">
<jmxName>smtpserversocketTLS</jmxName>
<bind>0.0.0.0:465</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="true" startTLS="false">
<keystore>file://conf/인증서.jks</keystore>
<keystoreType>JKS</keystoreType>
<secret>인증서 비밀번호</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectiontimeout>360</connectiontimeout>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<auth>
<announce>always</announce>
<requireSSL>true</requireSSL>
<plainAuthEnabled>true</plainAuthEnabled>
</auth>
<authorizedAddresses>127.0.0.0/8</authorizedAddresses>
<maxmessagesize>0</maxmessagesize>
<addressBracketsEnforcement>true</addressBracketsEnforcement>
<handlerchain>
<handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
<handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
</handlerchain>
</smtpserver>
</smtpservers>
smtpserver.xml
smtpserver가 3개다 이거는 보안설정 때문에 설정했다.
<bind> 부분이 포트설정이다. smtp는 총 3개의 포트가 존재한다.
25번 : 기본 smtp프로토콜번호, 보안이 없기에 해킹에 매우 취약하다.
465번, 587번 : 이는 보안 프로토콜로 분류되며, tls/ssl 종류에 따라 나뉜다.
내가 설정한 거 보면 465번은 soketTLS를 사용하며 587번은 startTLS를 사용한다.
인증서는 jks로 사용했으며 인증서 관련 생성해야 한다.
나는 let's encrypt라는 무료 인증서 생성 프로그램을 이용하여 인증서를 생성 후 keytool을 이용하여 인증서를 JKS로 변환하였다.(이 이외의 방법 했지만, 인증서 문제로 보안프로토콜이 작동이 안 되었다. 혹시 모르니 참고하는 게 좋을 거 같다.)
IMAP 설정하기
<?xml version="1.0"?>
<imapservers>
<imapserver enabled="true">
<jmxName>imapserver</jmxName>
<bind>0.0.0.0:143</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="false" startTLS="true">
<keystore>file://conf/인증서.jks</keystore>
<keystoreType>JKS</keystoreType>
<secret>인증서 비밀번호</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<plainAuthDisallowed>false</plainAuthDisallowed>
<auth>
<plainAuthEnabled>true</plainAuthEnabled>
</auth>
</imapserver>
<imapserver>
<jmxName>imapservertls</jmxName>
<bind>0.0.0.0:993</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="true" startTLS="false">
<keystore>file://conf/인증서.jks</keystore>
<keystoreType>JKS</keystoreType>
<secret>인증서 비밀번호</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<plainAuthDisallowed>false</plainAuthDisallowed>
<auth>
<plainAuthEnabled>true</plainAuthEnabled>
</auth>
</imapserver>
</imapservers>
imapserver.xml
IMAP도 SMTP와 똑같다고 보면 된다.
그다음은 데이터베이스 구축이다.
JAMES는 데이터베이스가 따로 존재하기 때문에 더 확장이 가능해진다. 이로 인해 웹메일로도 구축이 가능하다는 소리인 거다.
일단 데이터베이스 구축을 해본다. 나는 MariaDB를 사용했다. 설치방법은 인터넷에 널렸으니 그거 보면서 하면 좋다.
계정 생성 후 데이터베이스까지 만들어주면 된다.
JAMES와 DB연동하기
JAEMS와 DB까지 서로 연결해 주면 된다.
우선 드라이버를 설치해야 한다.
2024.04.20일 기준 드라이버 버전은 3.3.3이다, 아래 링크를 복사 후 우분투에 다운하면 된다.
https://dlm.mariadb.com/3752052/Connectors/java/connector-java-3.3.3/mariadb-connector-j-3.3.3.zip
압축 해제하면 mariadb-java-client-3.3.3.jar파일이 하나 나오는데 그 파일을
conf/lib 경로에 붙여 넣기하고 JAMES에서 설정해 주면 된다.
database.driverClassName=org.mariadb.jdbc.Driver
database.url=jdbc:mariadb://127.0.0.1:3306/DB이름
database.username=데이터베이스 사용자
database.password=사용자 비밀번호
vendorAdapter.database=MYSQL
openjpa.streaming=false
database.driverClassName은 우리가 다운로드한 드라이버 형태를 나타내는 거다.
database.uri는 우리가 만든 DB에 대한 경로이다. 드라이버 사용으로 DB연결이기 때문에 jdbc:mariadb://가 되며 그 뒤에는 내가 만든 DB에 대한 경로를 지정해 준다. 만약 같은 서버에 JAMES와 DB를 설치했으면 127.0.0.1:3306/myDB로 나타내면 된다. 3306은 DB에 대한 포트 번호이고, MariaDB는 3306이 기본 포트로 지정되어 있다.
database.username은 내가 만든 DB를 수정하고 관리 가능한 계정을 적으면 된다. 당연히 내가 만든 DB에 대한 모든 권한이 있어야 한다.
database.password는 계정 비밀번호를 적으면 된다.
vendorAdapter.database에는 데이터베이스 종류를 적으면 된다. MariaDB는 Mysql기반 동작하는 DB이기 때문에 mysql이라고 적어도 상관없고, 역시 드라이버 또한 mysql드라이버 사용해도 괜찮다.
다음은 이런 메일에 대한 정책 및 관련 설정을 하면 된다.
mailetcontainer.xml
<postmaster>postmaster@veno.kr</postmaster>
mailetcontainer.xml
메일을 가동하면 이 메일에 대한 관리자 메일 계정이다. 메일전송 실패 및 관련 메일 관리 도착 시 해당 메일 주소로 도착한다.
<mailet match="All" class="RemoteDelivery">
<delayTime>5000, 100000, 500000</delayTime>
<maxRetries>3</maxRetries>
<maxDnsProblemRetries>0</maxDnsProblemRetries>
<deliveryThreads>10</deliveryThreads>
<sendpartial>true</sendpartial>
<bounceProcessor>bounces</bounceProcessor>
</mailet>
mailetcontainer.xml
해당 부분을 찾아서 아래 코드를 넣으면 메일 설정에서 보안 관련 설정은 끝난 거다.
<outgoing>outgoing</outgoing>
<startTLS>true</startTLS>
<mail.smtp.ssl.trust>*</mail.smtp.ssl.trust>
mailetcontainer.xml
<mailet> 부분에 아무 데나 넣으면 된다.
이제 메일을 구동 후 사용자를 생성하면 된다.
JAMES구동하기
conf디렉터리에서 나와서 bin 디렉터리로 들어와서 메일을 가동해 본다.
sudo ./james start
관리자 권한으로 JAMES를 구동하면 된다.
정상작동 하는지 확인하려면 총 2가지를 확인해야 한다.
sudo netstat -anp | grep LISTEN
해당 명령어를 입력하여 우리가 추가한 보안 관련 설정한 포트가 등록되었는지 확인해야 한다.
smtp : 25, 465, 587
imap : 143, 993
총 5개가 있어야 한다.
그런 다음 서버에 대한 방화벽 설정을 하면 된다. 나는 서버를 가비아에서 대여 후 가동하는 거라 가비아에서 방화벽 설정을 해야 한다.
인바운드(들어오는 것) : 25, 143, 465, 587, 993
아웃바운드(나가는 것) : 25, 465, 587
smtp는 인바운드, 아웃바운드 둘 다 추가해야 한다.
다음은 로그를 확인해서 잘 돌 가는지 확인하면 된다.
log/wrapper.xml에 로그가 기록된다.
사진처럼
"org.apache.james.app.spring.JamesAppSpringMain.main:61 - Apache James Server is successfully started in 12140 milliseconds."이라고 뜨면 정상가동 중인 거다.
그다음 사용자를 추가해서 데이터베이스에 등록해야 한다.
sudo ./james-cli adduser test@veno.kr test123
james-cli라는 명령어로 adduser를 해서 이메일주소 비밀번호 하면 된다.
이러면 test라는 사용자에 test123이라는 비밀번호가 생성이 된다.
문제점 발견
다른 곳에서는 다루지 않았고, 공식문서도 뭐라 변명을 안 하시길래 걍 내가 해결했다.
아마 james-cli를 사용하면 아래와 같은 문구가 뜰 것이다.
Error: JAVA_HOME is not defined correctly.
We cannot execute
이 해당 오류는 james-cli에서 자바가 설치되어 있는 경로를 못 찾는 경우이다.
보다시피 JAVA_HOME이 올바르지 않다고 나온다. 그래서 쉘파일을 직접 수정해야 한다.
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`which java`
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." 1>&2
echo " We cannot execute $JAVACMD" 1>&2
exit 1
fi
해당 부분이 james-cli.sh에서 문제가 되는 부분 일부를 따온 거다.
우선 우리가 설치된 자바 종류에 따라 여러 개로 나뉜다. 만약 JDK폴더에 jre가 포함되어 있냐 없냐에 따라 경로를 JAVACMD로 할당해 주는데 else부분에 which java로 검색해 그걸 JAVACMD로 지정해 주는 거다.
보다시피 명령어로 검색해 보면 자바경로는 잘 뜨는데 james-cli가 거하게 반항한다. 어차피 경로는 무슨 일이 있어도 바뀌지 않으니 그냥 우리가 직접 할당해 주면 된다.
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`/usr/lib/jvm/java-11-openjdk-amd64/bin/java`
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." 1>&2
echo " We cannot execute $JAVACMD" 1>&2
exit 1
fi
JAVACMD를 그냥 수정만 해주면 된다. 그 후 다시 JAMES를 재가동시켜주면 james-cli는 정상적으로 동작한다.
이제 사용자 명령어를 입력 후 데이터베이스를 살펴보면 만든 DB안에 테이블이 자동으로 생성되었을 거다.
사용자는 정상적으로 등록된 걸로 보니 완벽히 다 된 거 같다.
내부 메일 전송 OK, 외부 메일은?
JAMES는 기본적으로 내부메일만 전송이 가능하도록 기본설정이 되어있다.
공기업, 군부대와 같이 네트워크가 단독적으로 작동하는 폐쇄망에서는 내부로만 메일이 전송이 된다. 이와 같은 개념이라고 생각하면 된다.
우선 정책부터 해제해야 한다.
<mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
<processor>relay-denied</processor>
<notice>550 - Requested action not taken: relaying denied</notice>
</mailet>
mailetcontainer.xml
이 부분을 아예 삭제하든, 주석처리하든 진행하면 된다.
그리고 도메인에 대한 설정을 해야 한다. 여기서 도메인란 것은 JAMES에 입력한 도메인이 아닌 내가 구매한 도메인에 대한 설정이다.
메일은 해킹사고가 많기 때문에 도메인 자체에 대한 신뢰하는 절차가 따로 있다.
1. MX레코드 설정
MX레코드는 @veno.kr 이라는 주소를 받을려면 역시 도메인이 담당한다. 그렇기 때문에 도메인으로 메일을 받을려면 MX레코드를 설정해줘야 한다. 쉽게 말해 "veno.kr은 메일주소고 @veno.kr로 메일을 보내면 veno.kr이 메일서버다"라고 이해하면 편하다
2. SPF레코드 설정
SPF는 내 메일서버를 등록해 주는 거다.
이건 MX와 헷갈릴 수 있을 거다. MX는 그냥 메일서버라는 것만 알려주는 거지 등록자체는 아니다. SPF는 veno.kr이라는 주소를 메일서버로 사용한다는 등록하는 개념이다.
3. Revers DNS
역학적 DNS라고 하는데 일반 DNS는 도메인→IP주소로 해주는 서비스이지만 ReversDNS는 IP→도메인으로 변환해 주는 DNS와 반대개념이다. 하지만 이는 우리가 직접 추가는 못하고 가비아나 Cafe24에서 해줘야 한다. 내가 해본 결과 Cafe24는 그런 거 못한다는 무능력한 답변을 들었다. 결국 가비아에 SOS를 치니 마음씨 고운 형님이 최대한 본인들이 할 수 있는 거 해본다고 해줬다. 그 결과 등록이 되었다.
이렇게 해주면 메일은 외부와 통신이 되면서 구글이나 네이버 등 여러 메일서비스와 서로 메일을 주고받을 수 있게 된 거다.
끝으로
이번꺼는 너무 대충 적은듯한 느낌이 든다. 메일 시스템 구축하고 상용화하기에는 엄청난 정성과 열정과 돈을 쏟아부어야 한다. 그만큼 정신적 고통이 제일 크다.
메일 시스템 구축이 다 끝나고 이제 웹메일이 남았다.
지금 개발 중이지만 꽤 복잡하다
내가 개발은 프론트엔드만 해서 세상을 개 만만하게 봤는데 웹메일을 구축하려고 보니 백엔드까지 하는 경이로운 광경은 보고 있었다.
현재 프론트는 플러터(Flutter), 백엔드는 Node.js(express), 데이터베이스는 Mysql(MariaDB)를 사용하여 개발 중인데, 로그인 구현만 해봤는데 뭔가 잘못된 느낌을 제대로 받았다. 개발자 꿈꾸는 병아리들아 빨랑 도망쳐라..
만약 이 블로그 보고 잘 모르겠으면 나한테
'리눅스, 네트워크' 카테고리의 다른 글
메일서버 - 서버에 메일시스템 설치하기 (0) | 2025.01.10 |
---|---|
메일서버 - 이론 기반 준비 (1) | 2025.01.05 |
메일서버 - 시작하기 (1) | 2024.03.24 |
정보보안 - AP (0) | 2023.08.13 |
메일서버 설정하기 - 동작원리 알기 (0) | 2022.08.10 |