Gentoo postfix dovecot sqlite

Gentoo Korea Wiki
Onionmixer (토론 | 기여)님의 2014년 4월 8일 (화) 10:14 판
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
둘러보기로 가기 검색하러 가기

목차

gentoo, postfix, dovecot, sqlite howto

개요

postfix 는 MTA(main transfer agent) 로서 qmail[1] 또는 exim[2] 및 전통적인 sendmail[3] 와 같은 역할을 하는 프로그램 집합이다.


dovecot 은 POP3 및 IMAP protocol 을 지원하는 서버로서 postfix 와 연동되어 사용되는 경우가 많은 범용서버이다.


sqlite 는 데이터베이스 당 단일파일로 구성된 sql database 엔진이다.


이 문서는 위의 구성으로 email account 를 실계정이 아닌 가상 계정으로 세팅해서 사용하는 email system 을 구성하는 방법을 설명하는것이 목적이다.


필요한 프로그램의 설치

postfix 설치는 아래와 같이 하면 된다.

USE="doc sqlite mbox dovecot-sasl" emerge postfix


dovecot 의 설치는 아래와 같이 하면 된다.

USE="imapc mbox mdbox sqlite" emerge dovecot


console 환경에서 email 테스트를 진행하기 위해 mailx 를 설치한다

emerge mailx


console 환경에서 mail 을 테스트하고싶다면 mutt 을 설치하는것이 좋다. mutt 은 오래된 curses 기반의 email client 이다.

emerge mutt


sqlite 데이터베이스의 초기화

먼저 sqlite 의 데이터베이스를 어디에 놓을지 위치를 결정해야한다. 이 문서에서는 /var/lib/postfix 를 경로로 사용한다.

데이터베이스 파일의 절대경로는 다음과같다.

/var/lib/postfix/postfix_database.sqlite


다음과 같은 명령어를 통해서 데이터베이스를 생성한다.

sqlite /var/lib/postfix/postfix_database.sqlite


참고로 데이터베이스 안에 아무것도 집어넣지 않는다면 sqlite 는 파일을 생성하지 않는다.


파일이 제대로 생성된 이후에는 파일의 owner 및 group 을 postfix 로 변경한다. 이 문서에서 세팅되는 owner 는 모두 postfix 를 사용하게 될것이기 때문이다.

chown postfix.postfix /var/lib/postfix/postfix_database.sqlite


sqlite 에 들어갈 sql 정보는 다른부분에서 별도로 언급하기로 한다.


postfix 의 기본설정

postfix 의 설정파일은 다음의 디렉토리에 있다.

/etc/postfix/main.cf


물론 이 아래 부분에서 설정을 진행하기전에 original 백업파일을 만들어놓는것을 잊지말자.

이 아래에는 main.cf 에서 중요한 부분만 일단 언급하는것으로 한다.

inet_interfaces = all
mydomain = aaa.com
myhostname = mail.aaa.com
mynetworks = 127.0.0.0/8, 172.16.1.0/24, 192.168.0.0/20
append_dot_mydomain = no
enable_long_queue_ids = yes
home_mailbox = Mail/
inet_protocols = ipv4
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
relay_domains = $mydestination
smtpd_banner = $myhostname ESMTP unknown
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, permit_inet_interfaces, reject_unauth_destination


postfix 의 기본설정을 테스트하기

아래의 명령어를 이용해서 세팅한 postfix 를 테스트해보기로 한다.

testaccount@localhost ~ $ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.yourdomain.com ESMTP unknown


위처럼 220 이라는 메세지가 나오면 일단 성공. 이제부터 테스트를 시작하도록 하자

EHLO aaa.com


아래와 같은 메시지를 확인할 수 있다면 성공.

250-mail.aaa.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN


이제 실제로 email 을 보내보기로 하자.

MAIL FROM:(내메일주소)
250 2.1.0 Ok
RCPT TO:(받는사람메일주소)
250 2.1.5 Ok
DATA(엔터키)
354 End data with <CR><LF>.<CR><LF>
SUBJECT:test email from new email server
sample email....
.
250 2.0.0 Ok: queued as 3dH3xl3cwgz9Kw7h7
^]  
telnet> quit


받는쪽에 email 이 도착한다면 메일을 보내는데는 성공했다고 봐도된다. 받는쪽의 email 이 google 또는 hotmail 등의 서비스라면 스팸함 으로 들어가는경우도 있으니 꼼꼼히 확인하도록 하자.


이제 gmail 등에서 여러분이 만든 system 상의 real account 로 email 을 보내보도록 하자. 만약 메일이 안들어가는것 같다면 mail daemon 의 log를 확인하도록 한다. 다음과 같은 부분이 나온다면 system 상에서 alias 관련된 데이터베이스를 생성해야한다는 의미가 된다.

Nov 10 01:52:03 [postfix/smtpd] warning: hash:/etc/mail/aliases is unavailable. open database /etc/mail/aliases.db: No such file or directory


이제 아래의 명령어를 이용해서 alias db 를 생성해주도록 한다.

newaliases


아래의 경로에 파일이 존재한다면 정상적으로 alias db 가 생성된것이 된다.

/etc/mail/aliases.db


자 이제 메일이 온것을 어디서 확인할 수 있을까? 만들어진 계정으로 login 해서 다음의 경로를 확인해보면 된다.

~/Mail/new/blahblah.(hostname)


파일이 존재한다면 외부 서버에서 정상적으로 email 이 들어온 것이라고 보면 된다.

이렇게까지 된다면 postfix 의 기본기능은 세팅이 되었다고 판단해도 된다.

물론 이 상태는 local 의 사용자끼리 email 을 주고받을 수 있는 상태이니 궁금하다면 테스트를 해봐도 좋다.


postfix 의 local 메일과 mutt 의 사용

아래의 주소를 참고한다


기본적으로 mutt 은 mail 을 spool directory 를 /var/spool/mail 에서 찾게되지만 postfix 는 각 계정의 Maildir 로 파일을 각각 넣어준다. 고로 mail spool 디렉터리를 별도로 지정해 주어야만 한다.

local 계정의 ~/.muttrc 라는 파일에 다음과같은 내용을 넣어준다.

set mbox_type=Maildir
set folder="~/Mail"

set mask="!^\\.[^.]"
set mbox="~/Mail"
set record="+.Sent"
set postponed="+.Drafts"
set spoolfile="~/Mail"

set pager_index_lines=4
set pager_format = " %C - %[%H:%M] %.20v, %s%* %?H? [%H] ?"

set menu_scroll=yes

color attachment blue white
color error red white
color hdrdefault black white
color indicator white black
color normal blue white
color tilde blue white
color quoted red white
color quoted1 brightred white
color quoted2 brightmagenta white
color quoted3 brightmagenta white
color quoted4 brightmagenta white
color quoted5 brightmagenta white
color signature red white
color status brightyellow blue
color markers red white
color header red white Subject 
color header red white From


이후 mutt 을 실행하면 도착한 email 을 확인할 수 있다.


postfix 는 Maildir[4] 이라는 규격을 사용한다. 이 이전에는 mbox 라는 규격이 사용되었으며 qmail 을 만든 제작자가 nfs 등의 상황에서 좀 더 유동적으로 반응할 수 있도록 Maildir 이라는 규격을 만들었다. 이런 부분을 참고하면 메일세팅을 좀 더 자유자재로 할 수 있을듯 하다.


postfix 의 디버깅

postfix 의 동작을 좀 더 자세히 디버깅하기 위해서는 다음의 파일을 편집하면 된다.

/etc/postfix/master.cf


위의 파일 내부에 다음과같은 line 이 있다.

smtp      inet  n       -       n       -       -       smtpd


이를 다음과같이 수정한다.

smtp      inet  n       -       n       -       -       smtpd -D


이렇게하면 postfix 에 대해 보다 자세한 동작 log 를 얻을 수 있다.

로그파일은 /var/log/mail/* 에 위치한다.(이 부분은 logger 에 따라 다를 수 있다. 본인은 metalog 를 사용한다)



sqlite 를 이용한 postfix 와 dovecot 의 세팅을 위한 사전지식

이 문서가 작성된 기본적인 목적은 postfix, dovecot, sqlite 를 사용함으로서 virtual mailbox 를 사용하게 하는것에 있다. 물론 virtual mailbox 라고해도 실제 메일이 sqlite 에 들어가는것은 아니다. 기본적으로는 email account 에 대한 계정정보를 sqlite 를 통해서 postfix 와 dovecot 사이에서 공유하는것에 있으며 실제로 메일은 서버상의 디렉토리안쪽에 나뉘어 들어가게 된다. 다만 차이점이 있다면 이 디렉토리는 postfix permission 으로 작동하게 되며 real account 를 사용하지 않기 때문에 ssh 접속등의 보안적인 측면에서 보다 좋은 장점을 얻게 된다.


postfix 에서 취급하는 mailbox와 domain 대한 개념

참고주소


local domain

일반적으로 가상메일박스등을 쓰지 않는 경우를 의미한다.

mydestination 의 값이 아래처럼 세팅되어있는 경우

mydestination = example.org, example.com, example.net


system 의 johndoe 라는 계정을 생성하게되면 다음의 3 가지 email 주소는 같은 메일함으로 취급된다.

johndoe@example.org
johndoe@example.com
johndoe@example.net


모두 /var/mail/johndoe 라는 위치의 메일함으로 들어가게 된다는 의미가 된다.


Virtual mailbox domains

이 경우는 email 의 account 가 /etc/passwd 의 영향을 받지 않는 상태를 의미한다.

virtual_mailbox_domains 의 값이 아래와 같이 세팅되어있는경우

virtual_mailbox_domains = example.org example.com


실제 email 이 들어가게되는건 아래와같은 경로로 들어가도록 취급된다.

john@example.org  /var/vmail/example.org/john/Maildir
jack@example.org  /var/vmail/example.org/jack/Maildir
jack@example.com  /var/vmail/example.com/jack/Maildir


위처럼 사용하려는 경우에는 /etc/postfix/virtual_mailbox_domains 파일에 내용이 추가되어야 한다.

example.org  OK
example.com  OK


각 domain 을 virtual mailbox 에서 허용한다는 의미가 되겠다.

이렇게 파일에 내용을 넣는걸로 끝나면 편하겠지만 그렇게 쉽게 가주지는 않는다. 파일의 내용이 세팅을 원하는 내용대로 된다면 다음과같은 compile 과정을 거쳐줘야 한다.

postmap /etc/postfix/virtual_mailbox_domains
postmap /etc/postfix/virtual_mailbox_users


postmap 을 이용해서 작업을 진행하면 .db 라는 확장자를 가진 파일을 만들어준다. postfix 는 이 과정을 자동으로 해주지는 않기때문에 이점에는 주의하는것이 좋다. 이렇게 만들어진 내용을 실제로 사용하기 위해서는 postfix 의 설정파일중 main.cf 에 다음과같은 내용을 추가해 주어야 한다.(hash라는 부분이 붙는것에 주의하는게 좋을듯 하다)

virtual_mailbox_domains = hash:/etc/postfix/virtual_mailbox_domains
virtual_mailbox_maps = hash:/etc/postfix/virtual_mailbox_users


다행히 database 를 사용하는 경우는 hash 를 사용하지않고 database 에서 값을 feedback 받기때문에 위와같은 복잡한 방법은 거치지 않아도 된다. 지금 작성하고 있는 이 부분에 대한 원문에서는 mysql 을 예로 들었지만 이 문서에서는 sqlite 를 사용하게 될것이기 때문에 이 부분에 대한 원래 문장은 인용하지 않는다. 다만 사용된 query 에 대해서는 간단하게 분석해봐야할 필요가 있다.

query = SELECT mailbox_path FROM virtual_users WHERE email_address='%s'


일단 아래의 페이지 2 개를 참고해보도록 하자.


일단 위의 query 구문에서 %s 는 입력값을 의미한다. 뭐가 입력되는지 모르는경우, 일반적으로 그냥 사용하는것 같다. 위 query 의 내용을 간단히 살펴보면 virtual_users 라는 데이터베이스 테이블에서 email_address 를 기준으로 검색을 진행해서 mailbox_path 라는 필드의 값을 반환하고 있다. 결과적으로 위 query 의 내용은 사용자의 virtual mailbox 의 경로를 알아내는것이 그 목적이라 할 수 있다. 이제 이렇게 작업된 파일을 실제로 postfix 의 main.cf 파일에 넣어보도록 하자.

virtual_mailbox_maps = $query/maps-vmbox.query


원문의 경우는 여기서 mysql 이라는 부분을 사용했지만 여기서는 postfix 를 기준으로 하고있기때문에 해당 문서의 내용을 기준으로 변경해보았다. 그럼 maps-vmbox.query 라는 파일에는 대체 어떤 내용이 있는걸까?

.query 파일을 살펴보기전에 postfix-sqlite 에 대해 설명한 내용의 main.cf 파일의 내용을 잠시 참고해야 할 필요가 있다. 해당 파일에는 다음과같은 내용이 있다.

query = sqlite:$config_directory/query


오호..... mysql 대신 이미 sqlite 라는 driver 부분이 선언되어있다. 이후 main.cf 파일내에서 $query 를 사용하는 부분은 전부 공통적으로 적용이 가능하다는걸 알 수 있다. 물론 내용을 잘 살펴보면 별도로 특별한 기술이 있는게 아니라 postfix 의 실행시 string replace 수준으로 작용된다라는걸 알 수 있다. 이제 정말로 maps-vmbox.query 라는 파일의 내용을 살펴보도록 하겠다.

dbpath = /etc/postfix/private/mail.sqlite
query = SELECT coalesce(VM.home, 'vmail/%d/%u')
	FROM VMailbox AS VM
	JOIN Address AS A1 ON VM.id=A1.id
	JOIN Domain AS D1 ON A1.domain=D1.id
	WHERE A1.localpart || '@' || D1.name IS '%s'
	AND VM.active!=0
result_format = %s/Mail/


첫번째줄에 sqlite 데이터베이스 파일의 path 부분이 정의되어있다.

두번째 줄에는 query 문장이 들어가있다. 두번째 줄을 보다보면 익숙하지 않은 것이 보인다. 다음의 내용을 잠시 참고하도록 한다.

coalesce(X,Y,...) coalesce() 함수는 Argument 중에서 첫번째로 Not Null 인 Argument 값을 리턴하는 함수입니다. 만일 모든 인자가 null 이면 null을 리턴합니다.


오호.. 뭔말인지 모르겠다! 사실 원문을 직역한 수준이기는한데.... 원문[5]을 보면 인수는 2 개 이상이어야 한다고 되어있다. 굳이 풀어보자면 VM.home 이라는 필드가 값이있으면 그걸 반환하고, VM.home 필드가 값을 가지고 있지 않으면 뒤에 나오는 'vmail/%d/%u' 이라는 값을 반환하게 되어있다.

이제 쿼리의 흐름을 살펴보기로 하자.

  • VMailbox 테이블의 id 필드와 Address 라는 테이블의 id 필드가 일치하며
  • Domain 이라는 테이블의 id 와 Address 라는 테이블의 domain 이라는 필드가 일치하는 데이터중
  • (Address 라는 테이블의 localpart + '@' + Domain 테이블의 name) 의 문자열 결합 결과가 '%s' 와 같으며
  • VMailbox 의 active 필드의 값이 0 이 아닌 데이터의 메일박스 경로를 반환한다.


위의 흐름에서 중요한간 localpart 가 곧 id 를 의미한다는것이 중요하다. 이 경우 인수로 주어지는 %s 는 "aaa@bbb.com" 정도의 값이 주어지게 되기때문에 id 와 domain 을 결합해서 해당되는 ID 의 virtual mailbox 값을 얻어내는것이 목적인 쿼리가 되겠다. 결과적으로 mysql 의 경우 얻는값과 별반 차이는 없다고 생각해도 무방하겠다.


세번째줄은 result_format 이라는 구문이 있다. 여기에도 %s 가 사용되는데 선택한 사용자의 virtual mailbox 값을 완성시키는 부분이라 보면 되곘다. 이후에 설명할 virtual_mailbox_base 의 값과 결합되면 다음과 같은 결과가 되겠다.

virtual_mailbox_base = /home
result_format = %s/Mail/


final :: /home/aaa@bbb.com/Mail/


Virtual alias domains

virtual mailbox 를 사용하는경우 에는 위에서 설명했다시피 local domain 을 사용하는것처럼 기본적으로 한개의 id 와 여러개의 domain 이 연결되지는 않는다. 이 경우 virtual alias domain 을 사용하게 된다. main.cf 파일 내에서는 virtual_alias_maps 라는것으로 설정되게 되는데 이 경우 인수의 처리 흐름은 왼쪽에서 오른쪽으로 가게 된다고 한다. 이런 기능은 다음과같은 3가지 경우를 대상으로 하게된다.


하나 : john@example.org 의 모든 email 을 jeff@example.com 로 포워딩 하는경우는 다음과같이 설정한다.

john@example.org   jeff@example.com


 : john@example.org 의 모든 email 을 jeff@example.com 로 포워딩 하지만 원래의 계정에도 이메일을 남겨놓는경우 다음과같이 설정한다.

john@example.org   john@example.org
john@example.org   jeff@example.com


간단하게 한줄로 작성할 수도 있다. 이 경우 콤마(,) 를 사용하면 된다.

john@example.org   john@example.org, jeff@example.com


 : example.org 도메인의 모든 메일을 joe@example.com 계정으로 포워딩하려면 다음과같이 설정한다.

@example.org   joe@example.com


지금까지 기본적인 virtual mailbox 에 대한 내용을 살펴보았다. 이 이후부터는 postfix, dovecot, sqlite 에 대한 세팅에 직접적으로 관련된 내용을 알아보도록 하겠다.


postfix, dovecot, sqlite 에 대한 자료

사실 sqlite 를 사용하지않는.... mysql 또는 postgreSQL 에 대한 내용은 인터넷상에서 심심치 않게 찾아볼 수 있다. 하지만 sqlite 를 기준으로 한 내용은 생각보다 많지않다. (사실 이 문서를 작성하기 시작한 원인이기도 하다) 현시점에서 가장 자료가 많은곳은 아래와 같다.


기본적으로 postfix 로 컨설팅을 하시는분의 홈페이지다. 정말 자료는 잘 되어있는데... 사실 dovecot 의 경우는 그다지 내용이 어렵지않은데 postfix 의 경우 어떤 부분이 어떤 역할을 하는지에 대한 학습이 필요하다. 물론 예제 자료는 잘 되어있지만 사용자가 원하는대로 세팅을 하기 위해서는 sqlite 데이터베이스에 들어갈 테이블 구조에 대한 고찰이 필요하다.


위의 rob 의 홈페이지에서는 이런부분에 대한 자세한 설명은 들어가 있지 않다. 본 문서에서는 이러한 부분에 대한 조금의 분석을 통해 원하는대로 데이터를 세팅하게 하는것을 목표로 한다.


postfix 와 sqlite 연동을 위한 디렉토리 및 파일의 구성

/etc/postfix/query/*


postfix 에서 sqlite 의 연동을 위해 사용하는 query 들이 들어가있는 디렉토리가 된다. 어떤 query file 들이 들어가는지는 아래에서 자세히 살펴보도록 한다.


smtpd restriction 에 대한 query 파일들

main.cf 에서 사용되는 smtpd_restriction_classes 에 대한 내용은 기본적으로 아래의 주소를 참고하도록 한다.


관련된 파일들의 정보는 다음과 같다

  • access-bscat.query >> smtpd_restriction_classes 관련파일
  • access-rcpt.query >> smtpd_recipient_restrictions 관련파일
  • access-rcptDomain.query >> smtpd_recipient_restrictions 관련파일


이 문서에서는 필터링에 대한것을 다루는것이 주 목적이 아니기때문에 이 부분은 지금 언급하지 않도록 한다.


그외 설정들에 대한 query 파일들
  • dom-local.query >> mydestination 에 대한 쿼리파일
  • dom-relay.query >> relay_domains 에 대한 쿼리파일
  • dom-valias.query >> virtual_alias_domains 에 대한 쿼리파일
  • dom-vmbox.query >> virtual_mailbox_domains 에 대한 쿼리파일
  • maps-alias.query >> alias_maps 에 대한 쿼리파일
  • maps-local.query >> local_recipient_maps 에 대한 쿼리파일. 모든 domain 을 sqlite 에서 제어하기 위해서는 사용해야하는 쿼리
  • maps-relay.query >> relay_recipient_maps 에 대한 쿼리파일. relay_domains 를 사용하지 않는 경우에는 주석처리하면 된다
  • maps-transport.query >> transport_maps 에 대한 쿼리파일. transport_maps 는 특정 domain 을 다른 smtp 등으로 보내는데 사용된다[6]. 사용하지 않는다면 주석처리하면 된다
  • maps-valias.query >> virtual_alias_maps 에 대한 쿼리파일. virtual mailbox 의 domain alias 와 관련이 있다.
  • maps-vgid.query >> virtual_gid_maps 에 대한 쿼리파일. mailbox 의 email account 에 대한 gid 와 관련이 있다.
  • maps-vmbox.query >> virtual_mailbox_maps 에 대한 쿼리파일. 직접적으로 virtual mailbox 에 대한 동작과 관련이 있다.
  • maps-vuid.query >> virtual_uid_maps 에 대한 쿼리파일. mailbox 의 email account 에 대한 uid 와 관련이 있다.


postfix 와 query 파일에서 사용하게될 sqlite 의 데이터베이스 schema

이제부터의 내용은 다음의 schema 내용을 기준으로 진행된다.

-- Mentioned in the old TODO file was that I wanted to do away with the
-- ugly unique column names and use plain words instead. Also mentioned
-- was the desire to improve the Transport and Alias tables. This is the
-- result: what the new schema should be. It surprised me!
--
-- New revision 2012-02-16 for those who are following along at home:
-- This removes the RClass table and foreign key constraints thereto,
-- because it is useless unless main.cf reads restriction classes from
-- the database.
--
PRAGMA foreign_keys=ON;
BEGIN TRANSACTION;
--
CREATE TABLE "Transport" (id INTEGER PRIMARY KEY,
	active INTEGER DEFAULT 1, transport TEXT, nexthop INTEGER,
	mx INTEGER DEFAULT 1, port INTEGER,
	UNIQUE (transport,nexthop,mx,port));
-- Transport.nexthop would be a pointer to Domain.id, but without a
-- foreign key constraint because the Domain table has yet to be
-- created at this point.
--
CREATE TABLE "Domain" (id INTEGER PRIMARY KEY, name TEXT,
	active INTEGER DEFAULT 1, class INTEGER DEFAULT 0,
	owner INTEGER DEFAULT 0, transport INTEGER,
	rclass INTEGER DEFAULT 30, UNIQUE (name),
	FOREIGN KEY(transport) REFERENCES Transport(id));
-- This revision removes the NOT NULL constraint from Domain.name; we
-- will insert a special record Domain.id=0 with Domain.name=NULL,
-- which thus maintains a defacto NOT NULL constraint for other rows.
INSERT INTO "Domain" VALUES(0,NULL,NULL,NULL,NULL,NULL,NULL);
--
CREATE TABLE "Address" (id INTEGER PRIMARY KEY,
	localpart TEXT NOT NULL, domain INTEGER NOT NULL,
	active INTEGER DEFAULT 1, transport INTEGER, rclass INTEGER,
	FOREIGN KEY(domain) REFERENCES Domain(id),
	FOREIGN KEY(transport) REFERENCES Transport(id),
	UNIQUE (localpart, domain));
-- We will insert a special record Address.id=0 with Address.domain=0
-- to differentiate aliases(5) commands, paths or includes from
-- address targets.
INSERT INTO "Address" VALUES(0,'root',0,NULL,NULL,NULL);
--
CREATE TABLE "Alias" (id INTEGER PRIMARY KEY,
	address INTEGER NOT NULL, active INTEGER DEFAULT 1,
	target INTEGER NOT NULL, extension TEXT,
	FOREIGN KEY(address) REFERENCES Address(id)
	FOREIGN KEY(target) REFERENCES Address(id)
	UNIQUE(address, target, extension));
-- This revision changes Alias.name to Alias.address, because INTEGER
-- fields should not be called "name" (to me that implies TEXT.) If
-- Alias.target=0, that tells us that the Alias.extension contains a
-- /file/name, or a |command, or an :include:/file/name. Otherwise,
-- Alias.extension contains an address extension.  Differentiation of
-- local(8) aliases(5) from virtual(5) is in the Address table, where
-- Address.domain=0, the special null record in the Domain table.
--
CREATE TABLE "VMailbox" (id INTEGER PRIMARY KEY,
	active INTEGER DEFAULT 1, uid INTEGER,
	gid INTEGER, home TEXT, password TEXT,
	FOREIGN KEY(id) REFERENCES Address(id));
--
CREATE TABLE "BScat" (id INTEGER PRIMARY KEY,
	sender TEXT NOT NULL, priority INTEGER,
	target TEXT NOT NULL, UNIQUE (sender, priority));
--
COMMIT;


각 테이블에 대한 역할은 다음과같다.

  • Transport 테이블
    • transport 기능을 사용하는 경우에 필요한 테이블
  • Domain 테이블
    • domain 에 대한 정보를 관리하는 테이블
  • Address 테이블
    • email account 와 domain 정보등을 연관지어 관리하는 테이블
    • id(localpart) 와 domain 필드를 pair 로 unique 로 처리한다. 개별 필드내에서 중복값은 허용하는 경우가 된다.
  • Alias 테이블
    • virtual mailbox alias 기능을 정의할때 사용되는 테이블
    • email주소(address), alias 처리할 대상(target), extenstion(alias 가 일어날때 별도로 동작시킬 수 있는 script등) 을 pair 로 unique 처리한다.
  • VMailbox 테이블
    • virtual mailbox 에 대한 email account 정보를 관리하는데 사용되는 테이블. email account 의 비밀번호, gid, uid 등이 이쪽에서 관리된다. ID 는 address 테이블에서 관리한다.
  • BScat 테이블
    • smtpd restriction 에 대한 정보를 담고있는 테이블


postfix 의 중요 query 파일 분석:map 관련 파일들

maps-alias.query

이 파일에서 사용되는 쿼리는 다음과 같다

query = SELECT ALL
	  CASE WHEN Alias.target=0 THEN Alias.extension
	  ELSE TA.localpart ||
	    (CASE WHEN Alias.extension IS NOT NULL THEN '-'
	      || Alias.extension ELSE '' END) ||
	    (CASE WHEN TD.id=0 THEN '' ELSE '@' || TD.name END)
	  END
	FROM "Alias"
	JOIN "Address" AS TA ON Alias.target=TA.id
	JOIN "Domain" AS TD ON TA.domain=TD.id
	JOIN "Address" AS AA ON Alias.address=AA.id
	WHERE AA.localpart IS '%s'
	AND AA.domain=0 AND Alias.active!=0;


위의 쿼리를 간단하게 분석해보자.

  • email 의 ID 부분을 검색용 인자로 받아서(%s)
  • Alias 테이블의 target 필드의 값이 Address 테이블의 id 와 같으며
  • Alias 테이블의 domain 필드의 값이 Domain 테이블의 id 와 같으며
  • Alias 테이블의 address 필드의 값이 Address 테이블의 id 와 같은 자료중에서
  • Address 테이블의 domain 필드의 값이 0 이며
  • Alias 테이블의 active 필드의 값이 0 이 아니며
  • Address 테이블의 localpart 의 값과 %s 의 값이 일치하는 데이터에 대해
  • 데이터의 Alias 테이블의 target 값이 0 인 경우는 Alias 테이블의 extension 필드의 값을 반환하고
  • 데이터의 Alias 테이블의 target 값이 0 이 아닌 경우에는 문자열을 결합해서 반환한다
    • Alias 테이블의 extentsion 이 공백이 아닌경우에는 '-' 문자 + extension 의 값을 반환
      • 공백이라면 를 반환
    • Domain 의 id 값이 0 이라면 공백을 반환.
      • 공백이 아니라면 '@' + domain 테이블의 name 필드 를 반환
    • 간단하게 보면 아래와 같다
      1. alias.extension 이 반환되거나
      2. Address.localpart-Alias.extension 이 반환되거나
      3. Address.localpart 이 반환되거나
      4. Address.localpart-Alias.extension@Domain.name 이 반환되거나
      5. Address.localpart@Domain.name 이 반환된다


이정도의 내용이 되겠다. 이중에서 Alias 테이블의 extension 은 뭐하는놈인지를 아직 모르겠으니 나중에 살펴보도록 하다.

결과적으로 위의 쿼리는 id 를 받아서 id 와 domain 이 연결된 주소를 반환하는 쿼리가 되겠다.


maps-local.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT localpart FROM Address
	WHERE localpart is '%s' AND domain=0 AND active!=0


오오 간단하다. 역시 분석해보자.

  • email 의 ID 부분을 검색용 인자로 받아서(%s)
  • localpart 와 id 과 같고
  • Address 테이블의 domain 값이 0 이며
  • Address 테이블의 active 값이 0 이 아닌 데이터의
  • localpart 필드를 반환한다.


이 쿼리는 입력받은 id 가 별도로 domain 을 사용하지않는 local 계정인지를 검색해서 반환하는 쿼리가 되겠다.


maps-valias.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT TA.localpart || (CASE WHEN VA.extension IS NOT NULL
	  THEN '-' || VA.extension ELSE '' END) ||
	  (CASE WHEN TD.id=0 THEN '' ELSE '@' || TD.name END)
	FROM Alias AS VA
	  JOIN Address AS TA ON (VA.target = TA.id)
	  JOIN Domain AS TD ON (TA.domain = TD.id)
	  JOIN Address AS AA ON (VA.address = AA.id)
	  JOIN Domain AS AD ON (AA.domain = AD.id)
	WHERE AA.localpart || '@' || AD.name IS '%s'
	AND VA.active!=0


이번에는 조금 길다. 하지만 분석해보도록 하자. (와아아 case 가 쓰이셨다.......)

  • email 전체를(aaa@bbb.com) 검색용 인자로 받아서(%s)
  • Alias 의 target 과 Address 의 id 가 같고
  • Address 의 domain 과 Domain 의 id 가 같으며
  • Alias 의 address 와 Address 의 id 가 같으며
  • Address 의 domain 과 Domain 의 id 가 같은 자료중에서
  • Address 의 localprt + '@' + domain.name 의 결합결과가 %s 와 같고
  • Alias 의 active 가 0 이 아닌 데이터에 대해
  • Alias.localpart 와 다른 문자열을 결합해서 반환한다
    • TA.localpart 와
    • Alias.extension 이 공백이 아닌경우 '-' + Alias.extension
    • Domain 의 id 값이 이 아닌경우 '@' + domain.name 을 결합한다
    • 간단하게 보면 아래와 같다
      • TA.localpart 가 반환되거나
      • TA.localpart-Alias.extension 이 반환되거나
      • TA.localpart@domain.name 이 반환되거나
      • TA.localpart-Alias.extension@domain.name 이 반환된다


이 쿼리는 email account 의 전체 주소를 받아서 id 또는 id@domain 을 반환하는 쿼리가 되겠다.


maps-vmbox.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT coalesce(VM.home, 'vmail/%d/%u')
	FROM VMailbox AS VM
	JOIN Address AS A1 ON VM.id=A1.id
	JOIN Domain AS D1 ON A1.domain=D1.id
	WHERE A1.localpart || '@' || D1.name IS '%s'
	AND VM.active!=0


이정도면 나름 준수한 편인거같다. 이 쿼리도 분석해보도록 하자.

  • email account 전체를(aaa@bbb.com) 검색용 인자로 받아서(%s)
  • Address 테이블의 id 필드와 VMailbox 의 id 필드가 같으며
  • Address 테이블의 domain 필드와 Domain 테이블의 id 필드가 같은 자료중에서
  • Address.localprt + '@' + Domain.name 의 결합결과가 %s 와 같으며
  • VMailbox 의 active 가 0 이 아닌 데이터에 대해
  • VMailbox.home 이 공백이 아니면 VMailbox.home 의 값을 반환하고
  • VMailbox.home 이 공백이라면 'vmail/%d/%u' 를 반환한다


위의 경우 %d 는 email 계정의 domain, %u 는 email 계정의 user 를 의미한다. aaa@bbb.com 의 경우

  • %u : aaa
  • %d : bbb.com


이런 결과가 된다. 이 쿼리는 입력된 사용자에 대한 mailbox 경로를 받아내는 쿼리가 되겠다.



postfix 의 중요 query 파일 분석:그외 domain 관련 쿼리파일들

dom-vmbox.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT Domain.name FROM Domain WHERE Domain.class>800
	AND Domain.active!=0 AND Domain.name IS '%s'


쿼리는 상대적으로 간단하다. 분석해보도록 하자.

  • domain 을 검색용 인자로 받아서(%s)
  • Domain.Class 가 800 이상이며
  • Domain 테이블의 active 값이 0 이 아니며
  • Domain 테이블의 name 이 %s 와 같은 결과의
  • Domain.name 을 반환한다.


이 쿼리는 입력된 domain 이 취급가능한 domain 인지를 조회해서 반환하는 역할을 하는 쿼리가 되겠다.

바로 아래쪽에서 살펴볼 dom-local.query 와 약간 비교되는데 Domain.clss 의 조건값이 틀리다. 결국 virtual domain 은 800 이상의 class 값을 가져야 한다.


dom-local.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT Domain.name FROM Domain WHERE Domain.class=1
	AND Domain.active!=0 AND Domain.name IS '%s'


쿼리는 dom-vmbox.query 와 비슷하다. 분석해보도록 하자.

  • domain 을 검색용 인자로 받아서(%s)
  • Domain.Class 가 1 이며
  • Domain 테이블의 active 값이 0 이 아니며
  • Domain 테이블의 name 이 %s 와 같은 결과의
  • Domain.name 을 반환한다.


이 쿼리는 main.cf 의 mydestination 부분에 사용된다. 일반적으로 mydestination 은 local domain 을 처리하는데 사용되며 이런 전제들을 살펴봤을때 local domain 으로 처리하기 위해서는 Domain.class 의 값은 1 이 되어야 하므로 local domain 은 데이터베이스 상에서 Domain.class 가 1 의 값을 가져야 한다는걸 알 수 있다.



dom-relay.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT Domain.name FROM Domain WHERE Domain.class=2
	AND Domain.active!=0 AND Domain.name IS '%s'


쿼리는 dom-local.query 와 비슷하다. 분석해보도록 하자.

  • domain 을 검색용 인자로 받아서(%s)
  • Domain.Class 가 2 이며
  • Domain 테이블의 active 값이 0 이 아니며
  • Domain 테이블의 name 이 %s 와 같은 결과의
  • Domain.name 을 반환한다.


이 쿼리는 dom-local.query 와 동일한 조건에서 Domain.class 가 2 인 domain 을 반환한다. 결과적으로 relay 가능한 domain 은 Domain.class 가 2 의 값을 가져야 한다는걸 알 수 있다. 이 쿼리는 main.cf 의 relay_domains 의 값으로 사용된다.


dom-valias.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT Domain.name FROM Domain WHERE Domain.class=3
	AND Domain.active!=0 AND Domain.name IS '%s'


쿼리는 dom-local.query 와 비슷하다. 분석해보도록 하자.

  • domain 을 검색용 인자로 받아서(%s)
  • Domain.Class 가 3 이며
  • Domain 테이블의 active 값이 0 이 아니며
  • Domain 테이블의 name 이 %s 와 같은 결과의
  • Domain.name 을 반환한다.


이 쿼리는 dom-local.query 와 동일한 조건에서 Domain.class 가 3 인 domain 을 반환한다. 결과적으로 alias 가 가능한 domain 은 Domain.class 가 3 의 값을 가져야 한다는걸 알 수 있다. 이 쿼리는 main.cf 의 virtual_alias_domains 의 값으로 사용된다.


postfix 의 중요 query 파일 분석:uid 및 gid 관련 파일들

maps-vuid.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT coalesce(VM.uid, D1.class)
	FROM VMailbox AS VM
	JOIN Address AS A1 ON VM.id=A1.id
	JOIN Domain AS D1 ON A1.domain=D1.id
	WHERE A1.localpart || '@' || D1.name IS '%s'
	AND VM.active!=0


조건은 그리 복잡하지 않지만 조금 주의해야할 부분이 있을거같다. 분석해보도록 하자.

  • email account 전체를(aaa@bbb.com) 검색 인자로 받아서(%s)
  • VMailbox 테이블의 id 필드와 Address 의 id 가 같으며
  • Address 테이블의 domain 필드와 Domain 테이블의 id 가 같은 자료중
  • Address.localprt + '@' + Domain.name 의 결합결과가 %s 와 같으며
  • VMailbox.active 의 값이 0 이 아닌 결과를 대상으로
  • VMailbox.uid 가 공백이 아닌경우에는 VMailbox.uid 를 반환하고
  • VMailbox.uid 가 공백인경우에는 Domain 의 class 필드의 값을 반환한다.


이 쿼리는 요청된 email account 의 uid 값을 반환하는 쿼리로서 값이 지정되어있으면 지정된 uid 값을 반환하고, uid 값이 별도로 지정되어있지 않은 경우에는 Domain 의 class 값을 uid 로 사용하게 되어있다.


maps-vgid.query

이 파일에서 사용되는 쿼리는 다음과 같다

SELECT coalesce(VM.gid, 800)
	FROM VMailbox AS VM
	JOIN Address AS A1 ON VM.id=A1.id
	JOIN Domain AS D1 ON A1.domain=D1.id
	WHERE A1.localpart || '@' || D1.name IS '%s'
	AND VM.active!=0


이 쿼리는 maps-vuid.query 와 비슷하지만 약간의 차이가 있다 분석해보도록 하자.

  • email account 전체를(aaa@bbb.com) 검색 인자로 받아서(%s)
  • VMailbox 테이블의 id 필드와 Address 의 id 가 같으며
  • Address 테이블의 domain 필드와 Domain 테이블의 id 가 같은 자료중
  • Address.localprt + '@' + Domain.name 의 결합결과가 %s 와 같으며
  • VMailbox.active 의 값이 0 이 아닌 결과를 대상으로
  • VMailbox.gid 가 공백이 아닌경우에는 VMailbox.gid 를 반환하고
  • VMailbox.gid 가 공백인경우에는 800 이라는 값을 반환한다.


이 쿼리는 요청된 email account 의 gid 값을 반환하는 쿼리로서 값이 지정되어있으면 지정된 gid 값을 반환하고, gid 값이 별도로 지정되어있지 않은 경우에는 800 이라는 gui 값을 강제로 사용하게 되어있다.


sqlite 를 사용하기 위한 postfix 의 map file 테스트

이제 database 를 연동하기전에 postfix 의 main.cf 에서 사용하는 각 field 를 테스트함으로서 실제 sqlite 데이터베이스에 어던 데이터가 들어가야하는지를 사전 테스트를 먼저 해보는것으로 진행하려 한다.


하나하나 기존에 있던 option 들을 portmap 이라는 postfix 의 프로그램을 통해 파일로 뽑아서 어떤형식으로 데이터가 유지되어야 하는지를 알아보도록 하겠다.


mydestination, relay_domains

기존의 mydestination 값은 다음과 같다.

mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain


이걸 다음과 같이 변경한다.

mydestination = hash:/etc/postfix/mapdatas/mydestinations
relay_domains = hash:/etc/postfix/mapdatas/relaydomains


그리고 /etc/postfix/mapdatas/mydestinations 파일의 내용을 다음과 같이 편집한다.[7](mapdatas 디렉토리가 없다고? 그냥 만들면 된다. 규칙이 딱히 정해져있는건 아니다)

mail.aaa.com    OK
localhost       OK
aaa.com         OK


그리고 /etc/postfix/mapdatas/relaydomains 파일의 내용을 다음과 같이 편집한다.

mail.aaa.com    1
localhost       1
aaa.com         1


편집이 끝나면 다음과 같은 명령을 실행해준다.

postmap /etc/postfix/mapdatas/mydestinations
postmap /etc/postfix/mapdatas/relaydomains


이제 외부에서 세팅한 서버로 email 을 보내보도록 한다.

email 이 local 의 서버까지 도착했다는걸 확인하면 mydestination 에 대한 hash 파일로의 변경은 성공했다고 봐도 된다. 기본적으로 mydestination 하나만 변경해봤자 어차피 relay_domains 가 제대로 설정되어있지 않으면 메일은 안쪽으로 도착하지 않는다. 고로 relay_domains 까지 설정해주어야 하는게 중점. 다만 widcard(* 기호) 는 사용할 수 없으니 필요한 domain 은 주르륵 적어주어야 한다.


virtual mailbox 에 대한 설정

이제부터 virtual mailbox 에 대한 세팅을 해보도록 한다. 순서대로 몇가지를 살펴보기로 한다.


일단 다음의 페이지를 참고한다.


위 페이지의 내용을 기준으로 작업을 진행해보도록 하겠다. 추가로 참고해둘것이 있다.

  • virtual alias 계열은 내 서버내에서 alias 를 처리할때 쓰인다.
  • virtual mailbox 계열은 내 서버내에서 virtual mailbox 의 메일을 처리할때 쓰인다.


차이점이 좀 미묘하지만.. 굳이 alias 를 사용하지 않을거라면 virtual_alias_* 는 사용하지 않아도 좋다.


virtual_alias_domains

main.cf 에 다음과같은 내용을 넣는다

virtual_alias_domains = hash:/etc/postfix/mapdatas/virtualaliasdomains


/etc/postfix/mapdatas/virtualaliasdomains 파일의 내용에 다음을 넣는다

mail.aaa.com         20131112
aaa.com              20131112


postmap 을 실행해서 만든 파일의 hash db 파일을 생성해준다.


virtual_alias_maps

위에서 이미 한번 언급했다시피 virtual mailbox 는 aaa@zzz.com 과 aaa@kkk.com 이 물리적으로 같은서버라고 하더라도 같은 계정으로 취급하지 않는다. 이 경우에 alias 를 사용해야 한다.

main.cf 에 다음과같은 내용을 넣는다

virtual_alias_maps = hash:/etc/postfix/mapdatas/virtualaliasmaps


/etc/postfix/mapdatas/virtualaliasmaps 파일의 내용에 다음을 넣는다

aaa@zzz.com     aaa@kkk.com


postmap 을 실행해서 만든 파일의 hash db 파일을 생성해준다.


물론 alias 를 별도로 사용하지 않을거라면 상관없다. 자세한 내용은 /etc/mail/aliases 관련된 내용을 검색해서 참고할것.


virtual_mailbox_domains

이제 virtual mailbox 를 사용하는 domain 을 세팅할 차례다.

main.cf 에 다음과같은 내용을 넣는다

virtual_mailbox_domains = hash:/etc/postfix/mapdatas/virtualmailboxdomains


/etc/postfix/mapdatas/virtualmailboxdomains 파일의 내용에 다음을 넣는다

aaa.com     OK


postmap 을 실행해서 만든 파일의 hash db 파일을 생성해준다.


virtual_mailbox_maps

이제 virtual mailbox 를 사용하는 계정(email account)에 대한 내용을 세팅해줄 차례다

main.cf 에 다음과같은 내용을 넣는다

virtual_mailbox_maps = hash:/etc/postfix/mapdatas/virtualmailboxmaps


/etc/postfix/mapdatas/virtualmailboxmaps 파일의 내용에 다음을 넣는다

bbb@aaa.com     aaa.com/bbb/


여기서 주의할점이 있다. aaa.com/bbb 가 되는경우는 bbb 라는 파일 자체가 수신한 email 파일이 되어버린다. 하지만 aaa.com/bbb/ 라고 정의하면 그 아래쪽에 Maildir 형식으로 디렉토리등을 생성하고 파일을 넣는다.


postmap 을 실행해서 만든 파일의 hash db 파일을 생성해준다.


virtual_mailbox_base

이제 virtual mailbox 의 파일들이 위치할 기본 디렉토리를 설정해줄 차례다.

virtual_mailbox_base = /home/virtualmailbox


물론 owner 를 변경해주어야 이후 메일폴더를 postfix 에서 생성할 수 있다.

chown -R postfix.postfix /home/virtualmailbox


virtual mailbox 를 위한 uid, gid 등의 설정

virtual mailbox 가 어떤 권한으로 유지되는지에 대한 설정이 필요하다. 왜냐하면 실제로 파일이 생성되기 때문이다.


아래와같이 설정한다.

virtual_minimum_uid = 100
virtual_uid_maps = static:207
virtual_gid_maps = static:207


여기서 207 은 필자 머신의 postfix 의 uid 및 gid 되시겠다.

어차피 나중에 postfix 와 dovecot 을 연동할때 dovecot 의 daemon 을 postfix owner 로 실행할거라 이렇게 하는게 속편할거라 생각한다.


설정파일 점검 및 테스트

위에서 살펴본 부분중 virtual mailbox 를 직접적으로 사용하기 위한 main.cf 내의 최소 내용은 다음과 같다.

virtual_mailbox_domains = hash:/etc/postfix/mapdatas/virtualmailboxdomains
virtual_mailbox_maps = hash:/etc/postfix/mapdatas/virtualmailboxmaps
virtual_mailbox_base = /home/virtualmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:207
virtual_gid_maps = static:207


여기에 몇가지 추가사항이 더 붙어야 한다.

$recipient_delimiter = '-';


위에서 설정한대로의 디렉토리를 생성해준다

mkdir /home/virtualmailbox/aaa.com/bbb/


물론 만들어진 directory 의 owner 를 postfix 변경해주는것을 잊지 말자.


외부에서 당신이 생성한 virtual mailbox 의 account 안쪽으로 email 이 들어오면 virtual mailbox 의 작업까지는 성공했다고 봐도 무방하다. 성공한경우에는 mail log 부분에 아래와같은게 표시된다.

Nov 12 17:37:48 [postfix/virtual] 3dJj5806Lwz9Kw6bY: to=<수신이메일주소>, relay=virtual, delay=1, delays=0.98/0/0/0.03, dsn=2.0.0, status=sent (delivered to maildir)
Nov 12 17:37:48 [postfix/qmgr] 3dJj5806Lwz9Kw6bY: removed


이로서 virtual mailbox 에 대한 hash 를 이용한 기본 테스트는 끝났다.

이제부터는 dovecot 과 인증정보 연동을 위한 postfix 의 setting values 를 알아보도록 하자.


postfix 와 dovecot 의 연동을 위한 설정 살펴보기

일단 http://rob0.nodns4.us/ 에서 제공되는 설정파일의 내용을 살펴보기로 하자.

submission_rcpt_restrictions = permit_sasl_authenticated,
	permit_mynetworks, reject
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot


위의 내용에서 RCPT 는 메일서버를 통해 메일을 받는다는것에 대한 정보를 의미한다.(아마도 receipt 의 약어라고 생각되지만) 기본적으로 postfix 나 dovecot 이나 원래는 system 상에서 제공되는 pam 을 이용한 account auth 를 진행하지만 이 문서에서는 real account 가 아닌 virtual mail account 를 사용할것이기 때문에 pam 을 사용하는것은 의미가 없다.

SASL 이란 Simple Authentication and Security Layer 의 약어로서 주로 메일 서버의 인증에 사용된다. postfix 도 마찬가지로 email 을 보내려는 사용자 에 대한 인증방법으로 sasl 을 사용할 수 있다. 위의 설정내용을 보면 알겠지만 sasl 의 type 으로 dovecot 을 지원하고 있다. 사용자에게서 인증요청이 postfix 를 대상으로 들어가면 postfix 는 dovecot 에게 요청해서 email account 인증을 지원한다는 의미가 된다. 고로 이건 mail receive 가 아니라 mail send(SMTP) 에 대한 설정이 되겠다 위와 같은 설정 하나만으로 postfix 를 이용한 SMTP 인증은 손쉽게 처리할 수 있다.


여기까지의 작업만으로도, 당신은 postfix 를 이용해서 email 을 외부에서 수신하고 dovecot 을 이용한 연동을 하기위한 기본지식을 익힐 수가 있었다.


postfix 와의 연동을 위한 dovecot 의 설정 살펴보기

dovecot 은 1.x 에서 2.x 로 버전이 올라오면서 기본적인 설정파일의 틀이 많이 바뀐듯 하다. 여기서는 dovecot 2.x 를 기준으로 설명하기도 한다. 1.x 에 대한 내용이 필요하다면.............. 인터넷에서 재주껏 찾아보기 바란다.


dovecot 의 설정에 필요한 기본 파일 구성은 다음과같다.

  • /etc/dovecot/dovecot.conf >> 기본 설정파일
  • /etc/dovecot/sql-deny.conf.ext >> dovecot 에서 deny=yes 로 세팅되어있는경우 사용되는 query 파일
  • /etc/dovecot/dovecot-sql.conf.ext >> sql 인증을 위한 데이터 베이스 정보가 있는 파일
  • /etc/dovecot/conf.d/10-auth.conf >> dovecot 을 통한 인증을 설정해주는 파일
  • /etc/dovecot/conf.d/auth-sql.conf.ext >> sql 을 통한 인증에 대한 세팅정보를 담고있다. 10-auth.conf 에서 사용된다.
  • /etc/dovecot/conf.d/auth-deny.conf.ext >> 10-auth.conf 에 include 되는 파일로서 사용자의 deny access 를 설정하는데 사용된다.
  • /etc/dovecot/conf.d/10-logging.conf >> dovecot 에 대한 디버깅 세팅정보를 담고있다.
  • /etc/dovecot/conf.d/10-mail.conf >> dovecot 에서 접근하게될 Maildir 에 대한 세팅정보를 가지고 있다.
  • /etc/dovecot/conf.d/10-master.conf >> pop3, imap, postfix 에 대한 인증정보등을 세팅한다.
  • /etc/dovecot/conf.d/10-ssl.conf >> ssl 인증서를 세팅하는 경우에 사용하면 된다.
  • /etc/dovecot/conf.d/20-imap.conf >> dovecot 에서 서비스하게될 imap 에 대한 세팅정보가 있다.


이 문서에서는 imap 만을 세팅하는것을 대상으로 하며 필요한 파일에 대한 수정부분만 별도로 언급하기로 한다.


10-auth.conf

!include auth-deny.conf.ext


위부분의 주석을 해제한다.


auth_mechanisms 부분에 cram-md5 를 추가해준다.


auth-deny.conf.ext

passdb {
  driver = passwd-file
  deny = yes

  # File contains a list of usernames, one per line
  args = /etc/dovecot/deny-users
}


위 부분을 추석처리한다.

passdb {
  driver = sql
  deny = yes

  args = /etc/dovecot/conf.d/sql-deny.conf.ext
}


sql 과 관련된 부분을 추가한다.


sql-deny.conf.ext

새로 파일을 만들고 아래의 내용을 추가한다.

driver = sqlite

connect = /var/lib/postfix/postfix_database.sqlite

### deny password_query
# The "deny=yes" passdb needs to handle either a "user@domain" or a
# plain "user" credential. In the former case, we look up the domain;
# latter case we use the special null domain, Domain.id=0. A simple glob
# expression to detect the "@" sign tells us which case we are in.

password_query = SELECT '%u' FROM Address AS A1 \
        JOIN Domain AS D1 ON (A1.domain=D1.id) \
        WHERE A1.localpart IS '%n' \
        AND (CASE WHEN '%u' GLOB '*@*' THEN \
                D1.name IS '%d' ELSE \
                D1.id=0 END) \
        AND A1.active=-1

# This is the third state of the tristate Address.active column.

# BUG: an "@" sign is permissible in an address localpart. This query
# works fine with SQL (virtual) users, because they have another "@" in
# their username anyway. But if your OS supports "@" in the username,
# this will break -- and you get to keep both pieces! I would not use
# "@" in system usernames, so I don't intend to fix this. :)

# end of sql-deny.conf.ext


dovecot-sql.conf.ext

아래의 내용을 참고해서 파일을 편집한다.

driver = sqlite
connect = /var/lib/postfix/postfix_database.sqlite
default_pass_scheme = MD5

password_query = SELECT '%u' AS user, V1.password, \
	coalesce(V1.uid, D1.class) AS userdb_uid, \
	coalesce(V1.gid, 800) AS userdb_gid, \
	'/home/virtualmailbox/' || coalesce(V1.home, 'vmail/%d/%n') AS userdb_home \
	FROM VMailbox AS V1 \
	JOIN Address AS A1 ON (V1.id=A1.id) \
	JOIN Domain AS D1 ON (A1.domain=D1.id) \
	WHERE A1.localpart IS '%n' \
	AND D1.name IS '%d' \
	AND V1.active!=0


user_query = SELECT coalesce(V1.uid, D1.class) AS uid, \
	coalesce(V1.gid, 800) AS gid, \
	'/home/virtualmailbox/' || coalesce(V1.home, 'vmail/%d/%n') AS home \
	FROM VMailbox AS V1 \
	JOIN Address AS A1 ON (v1.id=A1.id) \
	JOIN Domain AS D1 ON (A1.domain=D1.id) \
	WHERE A1.localpart IS '%n' \
	AND D1.name IS '%d' \
	AND V1.active!=0


윗부분에서 '/home/virtualmailbox/' 부분을 주의하도록 한다. postfix 에서 설정한 virtual_mailbox_base 와 같은 경로를 세팅해야 한다는것에 주의한다.


10-mail.conf

아래의 내용을 참고해서 파일을 편집한다.


mail_location = maildir:~/Mail

first_valid_uid = 207
last_valid_uid = 65535

first_valid_gid = 100
last_valid_gid = 65535

원문과는 다르게 first_valid_uid 는 207 로 설정하였다. 왜냐하면 postfix 의 uid 를 사용하기 때문이다.


10-master.conf

아래의 내용을 참고해서 파일을 편집한다.

unix_listener /var/spool/postfix/private/auth {
  mode = 0666
  user = postfix
  group = postfix
}

# Auth process is run as this user.
user = root


15-mailboxes.conf

중간쯤에 아래와 같은 부분을 추가해준다

inbox = yes


dovecot 에서 사용하는 sql 살펴보기

dovecot 에서의 sql 을 분석하기위해서는 wiki 페이지를 참고하는것이 좋다.

wiki 페이지를 참고할때 주의할점이 있다. dovecot 은 version 1 과 version 2 가 wiki 가 따로 나뉘어있다. 이 문서에서는 dovecot 2.x 를 기준으로 한다.


문서를 기준으로 다루는 쿼리의 인수에 대한 설명을 간단히 해보도록 하자. id 는 aaa@bbb.com 으로 기준해서 설명한다.

  • %u :: 사용자 id 전체를 의미한다. - aaa@bbb.com
  • %n :: 사용자의 id 를 의미한다. - aaa
  • %d :: 사용자 id 중 domain 부분을 의미한다. - bbb.com


sql-deny.conf.ext 에서 사용하는 쿼리

이제 사용되는 쿼리를 알아보자. 이 쿼리의 경우는 active 값을 -1 로 세팅해서 사용 불가능하게 만든 계정에 대한 정보를 return 받는 작업을 진행한다.

password_query = SELECT '%u' FROM Address AS A1 \
        JOIN Domain AS D1 ON (A1.domain=D1.id) \
        WHERE A1.localpart IS '%n' \
        AND (CASE WHEN '%u' GLOB '*@*' THEN \
                D1.name IS '%d' ELSE \
                D1.id=0 END) \
        AND A1.active=-1


오호.... 어차피 데이터베이스 테이블은 postfix 의 테이블을 같이 사용하기 때문에 postfix 의 테이블을 기준으로 알아보도록 하자.


인수로 주어진 것들을 기준으로 쿼리를 분석해 보면 다음과같다.

  • address 테이블의 domain 필드와 Domain 의 id 필드의 값이 같은 데이터를 대상으로
  • Address 의 localpart 필드와 사용자 id(%n) 이 같으며
  • %u(email account) 안에 @ 문자가 있는지를 확인해서
    • @ 문자가 있다면 domain 테이블의 name 필드에 domain 이 있는지를 확인하고
    • @ 문자가 없다면 domain 테이블의 id 가 0 인 데이터를 확인하며
  • Address 의 active 값이 -1 인경우를 확인해서
  • 데이터가 있다면 email account id 를 그대로 반환한다.


여기서 주의할점은 case when 에서 사용된 GLOB 이라는 연산자다. GLOB 이라는 연산자는 wildcard 를 사용해서 문자열 비교를 하는 유용한 함수다. LIKE 의 경우는 '%' 문자를 사용한다.


이 쿼리는 사용자의 id 를 입력받아 id 안에 domain 이 있는지를 확인하고 id 안에 domain 이 있다면 관련된값을, domain 이 없다면 domain 테이블의 id 값이 0 이며 active 가 -1 인 계정이 있는지를 찾아서 있으면 반환한다. 결과적으로 Address 테이블에서 비활성화된 계정을 찾아서 입력받은 사용자가 비활성화 계정인지를 확인해주는 쿼리가 되겠다.


dovecot-sql.conf.ext 에서 사용되는 쿼리

이 파일 내에서는 두개의 쿼리가 사용된다 쿼리별로 살펴보기로 하겠다. 원래 문서에는 password_query 다음에 user_query 가 명시되어있다. 왜냐하면 일단 password 인증을 하고나서 사용자 정보를 받아오는 순서가 되어야 하기 때문에 순서상으로는 그리 명시되어있다. 파일에서 명시한 순서대로 설명한다.


password_query

관련된 쿼리는 다음과 같다.

password_query = SELECT '%u' AS user, V1.password, \
	coalesce(V1.uid, D1.class) AS userdb_uid, \
	coalesce(V1.gid, 800) AS userdb_gid, \
	'/home/' || coalesce(V1.home, 'vmail/%d/%n') AS userdb_home \
	FROM VMailbox AS V1 \
	JOIN Address AS A1 ON (V1.id=A1.id) \
	JOIN Domain AS D1 ON (A1.domain=D1.id) \
	WHERE A1.localpart IS '%n' \
	AND D1.name IS '%d' \
	AND V1.active!=0

이번에는 내용이 좀 길지만 실제 내용은 별거없다. 이번에는 간단하게 반환값, 관련테이블(join), 검색조건 등으로 분석해보도록 하자.


  • 반환값
    • user 반환
      • 입력받은 email account id 를 그대로 user 로 반환한다.
    • password 반환
      • Address.password 값을 반환한다.
    • userdb_uid 반환
      • VMailbox.uid 값이 존재하면 그걸 userdb_uid 로 반환.
      • VMailbox.uid 값이 없다면 domain.class 를 userdb_uid 로 반환.
    • userdb_gid 반환
      • VMailbox.gid 값이 존재하면 그걸 userdb_gid 로 반환.
      • VMailbox.gid 값이 없다면 800 이라는 값을 userdb_gid 로 반환.
    • userdb_home 반환
      • VMailbox.home 값이 있다면 '/home/' + VMailbox.home 의 값을 userdb_home 으로 반환
      • VMailbox.home 값이 있다면 'vmail/%d/%n' + VMailbox.home 의 값을 userdb_home 으로 반환
  • table join
    • VMailbox.id 와 Address.id 가 일치하는 데이터와
    • Address.domain 과 Domain.id 가 일치하는 데이터의
    • VMailbox 테이블의 자료
  • 검색조건
    • Address.localpart 와 %n(id) 의 비교
    • Domain.name 이 같아야함
    • Address.active 값이 0 이 아니어야함


여기서는 userid,password,uid,gid,virtual mailbox 경로값 등 5개값을 반환하는것을 확인할 수 있다. 다만 위에서 설명한 sql-deny.conf.ext 에서 사용되는 쿼리 부분의 조건을 감안한다면 사용제한된 사용자는 한번 걸러지기 때문에 실제 사용하는 계정을 대상으로 검색조건이 이루어진다고 판단하면 된다.


이 쿼리는 일치하는 사용자를 찾아서 그에 해당하는 password 값을 포함한 다른값들을 반환하는 쿼리가 되겠다.


user_query

관련된 쿼리는 다음과같다.

user_query = SELECT coalesce(V1.uid, D1.class) AS uid, \
	coalesce(V1.gid, 800) AS gid, \
	'/home/' || coalesce(V1.home, 'vmail/%d/%n') AS home \
	FROM VMailbox AS V1 \
	JOIN Address AS A1 ON (v1.id=A1.id) \
	JOIN Domain AS D1 ON (A1.domain=D1.id) \
	WHERE A1.localpart IS '%n' \
	AND D1.name IS '%d' \
	AND V1.active!=0


위의 password_query 부분과 마찬가지로 반환값, 관련테이블(join), 검색조건 등으로 분석해보도록 하자.

  • 반환값
    • uid 반환
      • VMailbox.uid 값이 존재하면 그걸 uid 로 반환.
      • VMailbox.uid 값이 없다면 domain.class 를 uid 로 반환.
    • gid 반환
      • VMailbox.gid 값이 존재하면 그걸 gid 로 반환.
      • VMailbox.gid 값이 없다면 800 이라는 값을 gid 로 반환.
    • /home/ 관련된 반환
      • VMailbox.home 값이 있다면 '/home/' + VMailbox.home 의 값을 home 으로 반환
      • VMailbox.home 값이 있다면 'vmail/%d/%n' + VMailbox.home 의 값을 home 으로 반환
  • table join
    • VMailbox.id 와 Address.id 가 일치하는 데이터와
    • Address.domain 과 Domain.id 가 일치하는 데이터의
    • VMailbox 테이블의 자료
  • 검색조건
    • Address.localpart 와 %n(id) 의 비교
    • Domain.name 이 같아야함
    • Address.active 값이 0 이 아니어야함


이 결과로 봤을때 Address 테이블의 active 값이 0 이 아닌 사용자 계정의 데이터는 모두 검색 대상이 된다는걸 알 수 있다.


이 쿼리는 id 와 domain 값이 같은 활성화된 사용자를 검색해서 일치하는 사용자의 uid, gid, virtual mailbox 의 경로값을 반환하는 쿼리가 되겠다.


sqlite 에 데이터는 어떻게 넣어야 하나요?

지금부터는 sqlite 테이블에 데이터를 넣어서 vmailbox 의 값들을 이전처럼 hash 가 아닌 sqlite 에서 얻어오게 세팅함으로서 postfix 와 dovecot 의 연동을 위한 기초준비를 해보도록 하겠다. 일단 postfix 와 query 파일에서 사용하게될 sqlite 의 데이터베이스 schema 부분에서 설명한 테이블 구조를 기준으로 중요한 필드들에 대해 어떤값이 사용되어야 하는가를 알아보고 사용하게될 예제 데이터를 어떻게 넣어야 하는지를 살펴보도록 하자.

여기서는 모든 테이블의 값에 대해 언급하지는 않는다. 최소로 필요한 부분에 대해서만 조사하도록 한다.


데이터베이스 테이블에 대한 필드 값의 의미

Address 테이블

id :: 일반적으로 sql 에서 사용하는 seq 값의 의미다. Address 의 id 가 다른 테이블에서 큰 의미를 차지하는 경우는 없다.

localpart :: email account id 를 aaa@bbb.com' 이라고 했을때 aaa 부분에 해당된다

domain :: email account id 를 aaa@bbb.com' 이라고 했을때 bbb.com 부분에 해당된다. 다만 직접적으로 domain 이 들어가는것이 아니라 bbb.com 이라는 domain 은 이후에 언급할 domain 테이블에 들어가있게되며 이 값은 domain 테이블의 id 필드에 대해서 forign key 가 되므로 domain.id 의 값중에 하나가 되어야 한다. 모든 virtual mailbox 계정은 domain 값을 가지게 된다.

active :: 계정의 활성화 상태를 나타낸다. 0 이면 미사용, -1 이면 block, 0 이상이면 사용가능으로 분류된다.


Domain 테이블

id :: 다른테이블에서 forign key 로 사용된다.

active :: domain 의 활성화 상태를 나타낸다. 0 이면 미사용, 0 이상이면 사용가능으로 분류한다.

class :: 기본값은 0 이기는 한데..... virtual mailbox 에 사용되는 domain 들은 800 이상의 값을 가져야 한다. 고로 virtual mailbox 용 domain 은 801 부터의 값을 가지면 된다. 1 은 postfix 으 mydestination 에서, 2 는 relay_domains 에서 사용된다.[8]

name :: domain 의 이름이다. 실제 비교시에는 이 필드를 주로 참고하게 된다.


Domain 테이블은 address 테이블에서 domain 에 대한 정보로 참조되기위해 존재한다. 참조의 기준은 id 필드의 값이 된다.


VMailbox 테이블

id :: Account 테이블의 id 값과 같아야 한다. virtual mailbox 용으로 사용되기 위한 email account 는 Address.id 와 같은값의 VMailbox.id 데이터를 가지고 있어야 한다.

active :: virtual mailbox 의 활성화 상태를 나타낸다. 0 이면 미사용, 0 이상이면 사용가능으로 분류한다.

uid :: virtual mailbox 는 실제 unix 서버상의 폴더에 접근해야 하기때문에 uid 를 취급하게된다. postfix 에서는 Mailbox 형식에 맞춰 배달만 해주면 되기때문에 별로 까다로운 취급을 하지 않지만 dovecot 에서는 메일폴더에서 파일을 read/write 해야하기때문에 조금 더 관련이 깊다. dovecot 에서는 이 값이 지정되어있지 않은 경우에는 Domain 테이블의 class 값을 이 값으로 대체해서 사용한다. virtual mailbox 로 사용하기 원하는 account 라면 postfix 의 uid 와 통일시킬것을 권장한다.

gid :: 위의 uid 와 마찬가지 이유때문에 존재한다. dovecot 에서는 이 값이 지정되어있지 않는 경우 800 이라는 값을 강제로 사용한다. 이렇게하면 gid 값을 세팅하지 않은 email account 는 모두 800 이라는 그룹에 소속되게된다. 역시 가능하다면 postfix 의 gid 값을 사용해주는것이 좋겠다.

home :: virtual mailbox 에서 수신되는 메일들이 놓일 경로를 의미한다. 이 문서는 위[9]에서 이미 postfix 의 기본 동작 테스트를 위해 이 값을 세팅한적이 있다. 위에서는 aaa.com/bbb/ 라고 세팅한값이 이에 해당된다. 이 값은 virtual_mailbox_base 값과 같이 결합되어 반응한다.


password :: 이 부분은 굳이 가자면 설명이 복잡해진다[10]. 일단 간편하게 가기위해서 이 문서는 {PLAIN} 으로 사용하는것을 기준으로 설명하도록 하겠다. 실제 지금까지 세팅한 dovecot 의 내용도 이 값을 기준으로 설명하고 있다. email account 의 비밀번호를 kkk 로 하고싶다면 이 필드의 값을 {PLAIN}kkk 로 세팅해주면 된다.


테스트를 위한 sql 값의 세팅

이제 virtual mailbox 를 위한 sql 값을 세팅해보도록 한다. 세팅을 위한 기본 전제조건을 미리 정해놓고 세팅을 하는것이 좋다. 이제부터 전제조건의 예를 들어보자

  1. aaa 라는 id 를 사용한다.
  2. bbb.com 이라는 domain 을 사용한다.
  3. kkk 라는 비밀번호를 사용한다.


위의 조건에 몇가지 더 추가조건을 다시 생각해보자. 물론 이 문서의 윗부분에서 다뤘던 내용을 다시한번 간단하게 정리하는것뿐이지 기억이 잘 나지 않는다면 위의 내용을 살펴보도록 하자.

  1. virtual mailbox 로 사용할 domain 은 bbb.com 으로 정한다.
  2. virtual_mailbox_base 의 값은 /home/virtualmailbox 으로 정한다.
  3. virtual mailbox email account 의 실제 하드디스크상 위치는 /home/virtualmailbox/bbb.com/aaa 가 되는것으로 한다.
    • virtual mailbox 의 형식은 Maildir 이 된다.
    • 위에서 살펴본 query 파일중 maps-vmbox.query 파일을 기억하는가? 거기에는 result_format 이라는 항목이 있다.
    • 결과적으로 aaa@bbb.com 사용자의 email 배달 주소는 /home/virtualmailbox/bbb.com/aaa/Mail 이 된다. 참고하도록 하자
  4. system 에서 사용하는 postfix 의 uid 와 gid 는 207 로 정한다.


이 두 종류의 조건을 가지고 실제 테스트에 사용할 sql 을 만들면 다음과 같은 결과가 된다.

INSERT INTO "Domain" (id, name, active, class) VALUES (1,'bbb.com',1,801);
INSERT INTO "Address" (id, localpart, domain, active) VALUES (1, 'aaa', 1, 1);
INSERT INTO "VMailbox" (id, active, password, home, uid, gid) VALUES (
    (SELECT id FROM "Address" WHERE localpart IS 'aaa' AND domain=1),
    1,'{CRAM-MD5}445ee34964404bdba3d7d7fd1187839811699c8be7b71596f934141f721864d2','bbb.com/aaa',207,207);


여기서 주의할 부분이 있다. ssl/tls 를 사용하지 않는경우 대부분의 imap 을 지원하는 email client 또는 서버는 PLANE 방식의 비밀번호를 지원하지 않는다. 때문에 doveadm 이라는 프로그램을 사용해서 비밀번호를 넣어주어야 한다. 간단한 예제를 들어보자.

localhost # doveadm pw -pkkk -s CRAM-MD5 -u aaa@bbb.com
{CRAM-MD5}445ee34964404bdba3d7d7fd1187839811699c8be7b71596f934141f721864d2


형식은 그리 어렵지 않을거라 생각한다. dovocot 2 wiki 를 참고하기 바란다.[11].


이 내용을 sqlite 데이터베이스에 넣는다. 데이터베이스의 위치는 이미 몇번을 설명했듯이 아래와 같은 위치가 되겠다.

  • /var/lib/postfix/postfix_database.sqlite


sqlite 데이터베이스 파일의 위치를 postfix 의 각 쿼리파일 상단에 세팅해주는것을 잊지 말길 바란다!!!


세팅된 sql 값에 대한 검증

지금까지 sqlite 를 사용하기위한 쿼리와 데이터들을 알아봤다. 이미 위에서 설명한 내용을 잠시 복습해보자. virtual mailbox 를 사용하기 위한 postfix 의 최소 설정항목은 다음과 같다.

  • virtual_mailbox_domains
  • virtual_mailbox_maps
  • virtual_mailbox_base


맞다. 위에서 postfix 의 virtual mailbox 테스트를 진행할때 hash 값을 사용했던 값이 대부분이다. 이중에서 virtual_mailbox_base 는 쿼리로 대체할 값이 아니니 무시하도록 한다. 여기서는 virtual_mailbox_domains 와 virtual_mailbox_maps 에 대한 쿼리를 이용해서 입력한 값을 검증해 보기로 한다[12]. 위에서 설명한 query 를 기반으로 테스트용 query 를 만들어보면 다음과같은 내용이 될것이다.


이외에 테이블 설명을 참고로 다음의 항목을 설정해주면 좋다.

  • mydestination
  • relay_domains


테스트용 dom-vmbox.query
SELECT Domain.name FROM Domain WHERE Domain.class>800
	AND Domain.active!=0 AND Domain.name IS 'bbb.com';


이 쿼리의 테스트결과는 다음과같다.

bbb.com


테스트용 maps-vmbox.query
SELECT coalesce(VM.home, 'vmail/%d/%u')
	FROM VMailbox AS VM
	JOIN Address AS A1 ON VM.id=A1.id
	JOIN Domain AS D1 ON A1.domain=D1.id
	WHERE A1.localpart || '@' || D1.name IS 'aaa@bbb.com'
	AND VM.active!=0

이 쿼리의 테스트결과는 다음과같다.

bbb.com/aaa


일단 입력한 데이터가 원하는 작동을 한다는것을 알아냈다. 입력된 데이터도 정상이고 postfix 와 연동하는 쿼리를 수정없이 작동시켜도 이상이 없다는것을 확인했다. 이제 이 결과를 가지고 postfix 에서 sqlite 의 데이터베이스 연동이 정상인지를 확인해보도록 한다.


마지막단계::순서대로 테스트하기

postfix 와 sqlite 의 연동테스트

이 문서의 앞부분에서 postfix 의 virtual mailbox 연동을 위한 테스트를 했던걸 기억해보자. 일단 이전에 hash 로 세팅했던 값중에서 virtual_mailbox_domains 와 virtual_mailbox_maps 만 query 로 변경해서 적용해보도록 하자.

virtual_mailbox_domains = $query/dom-vmbox.query
virtual_mailbox_maps = $query/maps-vmbox.query
virtual_uid_maps = $query/maps-vuid.query
virtual_gid_maps = $query/maps-vgid.query


이제 외부에서 email 을 보내보자. 당신이 세팅한 대로 /home/virtualmailbox/bbb.com/aaa/Mail 이라는 디렉토리 아래쪽에 email 이 제대로 들어오는것을 확인했다면 postfix 와 sqlite 의 연동은 제대로 된것으로 확인해도 되겠다.


postfix 와 dovecot 의 인증의 연동

이제 외부에서 postfix 로 email 이 들어오는것을 확인했으니 smtp 인증 연동을 작업해봐야 한다. 다음의 내용을 postfix 의 main.cf 에 추가해준다.

smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_local_domain = $mydomain
smtpd_sasl_security_options = noanonymous
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot


postfix 를 재시작한다.


dovecot 과 sqlite 의 연동테스트

dovecot 의 경우에는 애초에 sqlite 와 연동하는것을 목표로 세팅했기 때문에 별도로 테스트를 위해 세팅을 바꿔야 할것은 없다. thunderbird 등의 imap 을 지원하는 email client 를 준비하고 imap 연결을 준비한다. 그리고 postfix 에서 테스트할때 확인했던 메일이 email client 에서 보이는지를 확인한다.


그리고 email client 프로그램을 이용해서 외부로 email 이 제대로 전송되는지도 확인한다.


tip::telnet 으로 imap 을 테스트하자

dovecot 이 마음대로 되지 않는다고 판단될때.. 일반적인 email client 는 에레메시지를 명확하게 내뱉어주지도 않을뿐더러 별도의 smtp 를 준비하지않으면 smtp 오류인지 어떤 오류인지 테스트하기 좀 귀찮을때가 있다. 그럴때는 telnet 을 통해 다음과같이 간단한 테스트를 진행할 수 있다.

telnet localhost 143

1 login aaa@bbb.com kkk

2 select INBOX


물론 맨 앞부분의 숫자까지 입력을 해줘야하는게 맞다. kkk 는 비밀번호에 해당한다. 다만 위의 방법은 plain password 방식이기때문에 비밀번호는 정상인데 다른 부분이 이상한 경우에 사용하도록 한다.


결론

지금까지 이런저런 내용을 세팅해가며 postfix, dovecot, sqlite 의 연동에 대해 알아보았다. 사실 이 외에도 몇가지 신경써야 하는 부분이 아직 더 남아있을 수 있지만 지금까지의 내용만으로 독자가 원하는 email 작업을 하는데는 충분히 문제가 없다. 몇가지 주의점을 언급함으로서 이 문서를 마칠까 한다.

  1. thunderbird 를 사용하는경우 암호화 방식을 암호화된 패스워드 로 사용하는 경우에는 서버에서 반드시 CRAM-MD5 를 지원해야한다.
  2. sqlite database 파일은 반드시 web 등에서 직접적으로 접근이 불가능한곳에 놓아야한다. postfix 로 owner 를 바꿔주는것 역시 잊지 말아야 한다.
  3. 서버상에 존재하는 virtual mailbox email directory 는 사실 sql 의 연동까지 다 끝나면 자동으로 생성되니 일일히 디렉토리를 생성해줘야할 필요는 없다.


이렇게 세팅을 해서 만들어진 postfix 의 main.cf 파일에 대한 추가부분을 올려둔다. 필요한경우 참고하면 되겠다.

#========================================================
# custom setting values
#========================================================

inet_interfaces = all
mydomain = bbb.com
myhostname = mail.bbb.com
myorigin = $myhostname
mynetworks = 127.0.0.0/8, 172.16.1.0/24, 192.168.0.0/20
append_dot_mydomain = no
enable_long_queue_ids = yes
home_mailbox = Mail/
inet_protocols = ipv4
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#relay_domains = $mydestination
smtpd_banner = $myhostname ESMTP unknown
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, permit_inet_interfaces, reject_unauth_destination



#========================================================
# custom setting values for dovecot and sqlite
#========================================================


mydestination = hash:/etc/postfix/mapdatas/mydestinations
relay_domains = hash:/etc/postfix/mapdatas/relaydomains

query = sqlite:$config_directory/query

virtual_mailbox_domains = $query/dom-vmbox.query
virtual_mailbox_maps = $query/maps-vmbox.query
virtual_uid_maps = $query/maps-vuid.query
virtual_gid_maps = $query/maps-vgid.query
virtual_mailbox_base = /home/virtualmailbox
virtual_minimum_uid = 100
$recipient_delimiter = '-';

smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_local_domain = $mydomain
smtpd_sasl_security_options = noanonymous
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot


부족한 문서를 읽어주셔서 감사드립니다. 해보니깐 보통이 아니군요. 대략 한달.. 넘게 걸린거같습니다. 문서에 대한 문의사항이 있으시다면 http://gentoo-kr.org 로 부탁드립니다. 감사합니다.


참고자료


Notes

  1. http://www.qmail.org
  2. http://www.exim.org
  3. http://www.sendmail.org
  4. http://en.wikipedia.org/wiki/Maildir
  5. http://www.sqlite.org/lang_corefunc.html
  6. http://www.postfix.org/STANDARD_CONFIGURATION_README.html 페이지의 Running Postfix behind a firewall 부분의 설정파일 참고
  7. http://www.irbs.net/internet/postfix/0401/1694.html
  8. virtual mailbox 에 대한 부분은 dom-vmbox.query 설명 부분을 참고하도록 한다. local domain 에 대한 부분은 dom-local.query 부분을 참고한다.
  9. virtual_mailbox_maps 부분을 참고한다.
  10. http://wiki2.dovecot.org/Authentication/PasswordSchemes 주소를 참고한다
  11. http://wiki2.dovecot.org/Tools/Doveadm/Pw 주소를 참고한다. 사용 가능한 비밀번호 암호화 방식의 종류는 http://wiki2.dovecot.org/Authentication/PasswordSchemes 주소를 참고한다.
  12. 물론 relay_domains 와 mydestination 에 대한 테스트도 같이 해주면 좋다