메일 서버 · 11 min read · Jan 04, 2026

Postfix, Courier 및 MySQL과 함께하는 가상 사용자 및 도메인에 대한 자동 응답기

Postfix, Courier 및 MySQL과 함께하는 가상 사용자 및 도메인에 대한 자동 응답기

이 가이드는 Yaa!(Yet Another Autoresponder!)가 Debian Sarge와 Postfix 튜토리얼의 가상 사용자와 함께 작동하도록 하는 데 중점을 둡니다 (https://www.howtoforge.com/virtual_postfix_mysql_quota_courier 참조).

가이드에 대해 이해해야 할 첫 번째 사항은 Virtual Delivery Agent(VDA)를 사용하며, 그 결과 .forward 파일을 통해 파이프에 전달하여 사용할 수 있는 자동 응답기가 VDA가 .forward 확장을 지원하지 않기 때문에 작동하지 않는다는 것입니다. 이 제한은 Procmail/Maildrop 배달을 통해 극복할 수 있지만, 이는 복잡하고 특히 많이 사용되는 메일 시스템에서는 느립니다. 간단한 대답은 Yaa!입니다!

Yaa를 다운로드하고 파티를 시작합시다:

mkdir -p /usr/local/postfix-tools 
cd /usr/local/postfix-tools
wget http://frost.ath.cx/software/yaa/dist/yaa-0.3.tar.bz2
tar jxvf yaa-0.3.tar.bz2

다음으로 Yaa가 작동하도록 필요한 Perl 모듈을 가져와야 합니다. Yaa는 데몬 모드에서 작동하지만 이 가이드에서는 프로그램의 비데몬 모드에 대해서만 다룰 것입니다.

apt-get install libmldbm-perl libio-lockedfile-perl libnet-perl libcarp-clan-perl libdbi-perl libdbd-mysql-perl libnet-server-perl libio-stringy-perl

Yaa가 작동하도록 데이터베이스 구조를 설정합시다:

mysql -uroot -p
use mail;
CREATE TABLE `autoresponder` (  
`active` tinyint(1) NOT NULL default '0',  
`message` mediumtext NOT NULL,  
`subject` varchar(250) NOT NULL default '',  
`charset` varchar(250) NOT NULL default '',  
`forward` varchar(250) NOT NULL default '',  
`address` varchar(250) NOT NULL default '',  
`local_domains` varchar(250) NOT NULL default '',  
`tstart` int(32) NOT NULL default '0',  
`tfinish` int(32) NOT NULL default '0',  
PRIMARY KEY (`address`),  
KEY `active` (`active`),  
KEY `tstart` (`tstart`,`tfinish`)  
)
quit;

다음으로 Postfix를 구성하여 Yaa!를 전송하도록 호출해야 하므로 /etc/postfix/master.cf를 편집하여 다음을 추가해야 합니다:

 # yaa autoresponder  
yaa     unix    -       n       n       -       -       pipe  
                                                user=vmail  
                                                argv=/usr/local/postfix-tools/yaa-0.3/bin/yaa.pl

변경 사항을 적용하기 위해 Postfix를 재시작합시다:

/etc/init.d/postfix restart

마지막으로 Yaa!를 구성해야 합니다. 쉽게 하기 위해 제 yaa.conf를 제공했습니다.

######################################################  
#                 !!!!WARNING!!!!                    #  
#  다음 줄을 제거하거나 주석 처리하지 마십시오   #  
use strict;                                          #  
######################################################  
  
# NOTICE:  
# yaa.pl을 실행하는 데 문제가 있고  
# 무엇이 잘못되었는지 확실하지 않은 경우 환경 변수를 설정하십시오  
#  
#                   YAA_DEBUG  
#  
# 같은 인수/구성 파일로 yaa.pl을 다시 실행하십시오.  
#  
# Yaa 디버그 출력은 단일 메시지 처리 모드에서 stderr에 기록됩니다  
# 또는 $daemon_background = 0인 경우 데몬 모드에서.  
#   
# $daemon_background = 1인 경우 디버그 메시지가  
# 로거 하위 시스템으로 전송됩니다.  
#  
# csh의 예:  
# setenv YAA_DEBUG 1  
#  
# sh/ksh/bash의 예:  
# export YAA_DEBUG=1  
#  
  
# 일반 참고 사항  
#   
# 훌륭한 오픈 소스 프로젝트의 구성 파일에서 발췌  
# amavisd-new   
# Mark Martinec .  
#   
# 이 파일은 Perl 자체에 의해 해석되는 일반 Perl 코드입니다.  
# - 이 파일(또는 그 위치에 있는 디렉토리)이  
# 일반 사용자가 쓰기 가능하지 않도록 하십시오. 그렇지 않으면 심각한 보안 위험을 초래합니다!  
# - 부울로 해석되는 값의 경우  
# 1을 true로 사용하고 0 또는 undef 또는 ''를 false로 사용하는 것이 좋습니다.  
# - Perl 구문이 적용됩니다. 특히:  
# 문자열은 ""에 포함될 수 있는 변수를 포함할 수 있습니다  
# ($ 또는 @로 시작); 이중 인용된 문자열에서 @ 및 $ 문자를 포함하려면  
# 백슬래시로 앞서야 합니다; 단일 인용된 문자열에서는  
# $ 및 @가 특별한 의미를 잃으므로 일반적으로 단일 인용 문자열을 사용하는 것이 더 쉽습니다.  
# 그럼에도 불구하고 두 경우 모두 백슬래시는 두 번 사용해야 합니다.  
  
######################################################  
#           로깅 하위 시스템 설정               #  
######################################################  
  
# 로깅을 활성화합니까?  
# 유형: 부울  
# 기본값: 1  
# $logging = 1;  
  
# syslog에 로깅을 활성화합니까?  
# 유형: 부울  
# 기본값: 1  
$log_syslog = 1;  
  
# syslog 로깅 시설  
# 유형: 문자열  
# 기본값: "mail"  
# 이 설정은 syslog에 로깅할 때만 적용됩니다  
# $log_syslog_facility = "mail";  
  
# syslog 로깅 우선 순위  
# 유형: 문자열  
# 기본값: "info"  
# 이 설정은 syslog에 로깅할 때만 적용됩니다  
# $log_syslog_priority = "info";  
  
# 평문 파일에 로깅합니까?  
# 유형: 부울  
# 기본값: 0  
#$log_file = 1;  
  
# 로그 파일 이름  
# 유형: 문자열  
# 기본값: undef  
# 이 설정은 파일에 로깅할 때만 적용됩니다  
#$log_file_filename = "/var/log/yaa.log";  
  
# stderr에 로깅합니까?  
# 유형: 부울  
# 기본값: 0  
# !!!! 경고 !!!!  
# yaa 디버깅이 켜져 있을 때(환경 변수 YAA_DEBUG가 설정됨)  
# STDERR 출력은 로거 하위 시스템에 매핑되며 실제 stderr에는 아무것도 표시되지 않습니다.  
# 따라서 syslog 또는 파일 기반 로깅을 설정해야 합니다.  
# !!!! 경고 !!!!  
# $log_stderr = 0;  
  
# 파일에 로깅할 때 로깅 시간 형식  
# 유형: 문자열  
# 기본값: "[%a, %b %e %T %Y]: "  
# 자세한 내용은 strftime(3)을 참조하십시오  
# $log_time_format = undef;  
  
######################################################  
#               데몬 모드 설정                 #  
######################################################  
  
# 데몬으로 실행합니까?  
# 유형: 부울  
# 기본값: 0, 데몬으로 실행하지 않음  
# 이 설정은 데몬 모드 작동을 활성화합니다.  
# $daemon = 1;  
  
$daemon = 0;  
$daemon_lockfile = "/tmp/yaa.lock";  
$daemon_pidfile = "/tmp/yaa.pid";  
$daemon_tcpserver_loglevel = 4;  
  
# 데몬으로 실행할 때 백그라운드로 포크합니까?  
# 기본값: 1  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_background = 1;  
  
# 데몬 수락 잠금 파일  
# 유형: 문자열  
# 기본값: "/var/lock/yaa.lock"  
# 이 설정은 데몬 모드에서만 적용됩니다  
# 경고: chroot 감옥에서 실행하는 경우 이 옵션은  
# chroot 디렉토리에 상대적으로 설정해야 합니다  
# $daemon_lockfile = "/tmp/yaa.lock";  
  
# 데몬 pid 파일  
# 유형: 문자열  
# 기본값: "/var/run/yaa.lock"  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_pidfile = "/tmp/yaa.pid";  
  
# 최소 yaa 자식 프로세스 수  
# 유형: 정수  
# 기본값: 2  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_min_servers = 2;  
  
# 최대 yaa 자식 프로세스 수  
# 유형: 정수  
# 기본값: 3  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_max_servers = 3;  
  
# 최소 yaa 여유 자식 프로세스 수  
# 유형: 정수  
# 기본값: 1  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_min_spare_servers = 0;  
  
# 최대 yaa 여유 자식 프로세스 수  
# 유형: 정수  
# 기본값: 1  
# 이 설정은 데몬 모드에서만 적용됩니다  
#$daemon_max_spare_servers = 1;  
  
# 데몬 통신 프로토콜  
# 유형: 문자열  
# MTA가 yaa와 통신하는 데 사용하는 프로토콜  
#  
# NOTICE: 이 구성 매개변수의 가능한 값은 RUN  
# yaa.pl --list-transport-protocols  
#  
# 기본값: "SMTP"  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_protocol = "LMTP";  
  
# yaa가 수신해야 하는 tcp 수신 포트 또는 유닉스 도메인 소켓  
# 유형: 정수/문자열  
# 기본값: 40000  
# 유닉스 도메인 소켓을 지정하려면 값을 다음과 같이 설정하십시오: '/path/to/socket|unix'  
#  
# 또한: perldoc Net::Server::Proto  
#  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_listen_port = 40000;  
  
# yaa가 바인딩해야 하는 호스트 이름.  
# 유형: 문자열  
# 기본값: "localhost"  
# 이 설정은 데몬 모드에서만 적용됩니다  
# $daemon_listen_host = "127.0.0.1";  
  
# 데몬 tcpserver (Net::Server) 로그 수준  
# 유형: 정수  
# 기본값: 0  
# 'O' => 로깅 비활성화  
# 0 => 'err'  
# 1 => 'warning'  
# 2 => 'notice'  
# 3 => 'info'  
# 4 => 'debug'  
$daemon_tcpserver_loglevel = 4;  
  
######################################################  
#               YAA 객체 설정                  #  
######################################################  
  
# 자동 응답 메시지 전송 시간 데이터베이스를 저장하는 데 사용되는 디렉토리.  
# 유형: 문자열  
# 기본값: "/tmp"  
# !!!! 경고 !!!!  
#   - yaa가 chrooted 상태에서 실행되는 경우(구성 변수 $chroot 참조),  
#      이 변수를 chroot 디렉토리에 상대적인 값으로 설정해야 합니다  
#   - 디렉토리는 메시지 처리를 위해 yaa가 사용하는 uid/gid에 대해 쓰기 가능해야 합니다  
#     $user 및 $group 변수도 참조하십시오  
#  
# !!!! 경고 !!!!  
# $db_dir = "/db";  
  
# 자동 응답자가 켜져 있는 메시지 수신자로부터 동일한 메시지 발신자에게  
# 자동 응답이 전송되는 사이의 시간(초).  
#   
# !!!! 경고 !!!!  
#  테스트 목적으로 -1로 설정(시간 확인 끄기),  
# 그러나 프로덕션 시스템에서는 이 값을 3600(1시간)보다 낮게 설정하지 마십시오 !!!!  
#   
# !!!! 경고 !!!!  
# 유형: 정수  
# 기본값: 7200  
# $duration_interval = 24 * 60 * 60;  
$duration_interval = "-1";  
  
######################################################  
#             자동 응답 설정                  #  
######################################################  
  
# 자동 응답 및 메시지 전달에 사용되는 방법  
# 유형: 문자열  
# 가능한 값: "smtp", "sendmail"  
# - "smtp"는 smtp 서버를 사용하여 메일을 보냅니다  
# - "sendmail"은 메일을 보내기 위해 sendmail 바이너리를 호출합니다  
#  
# !!!!경고!!!!: sendmail 전송 방법을 사용할 때 이상한 일이 발생합니다  
# 데몬 모드에서 실행할 때!  
#  
# 기본값: "smtp"  
# $mail_sending_method = "smtp";  
  
# sendmail 프로그램 경로  
# 유형 문자열  
# 기본값: $PATH 환경 변수에서 자동으로 검색됨;  
# $PATH에서 찾을 수 없는 경우 undef.  
#$sendmail_path = undef;  
  
# SMTP 서버 설정  
# 유형: 문자열  
#  
# perldoc Net::SMTP도 참조하십시오  
#  
# 기본값: localhost  
# $smtp_server = "localhost";  
  
# SMTP 인증 사용?  
# 유형: 부울  
# 기본값: 0  
# $smtp_auth = 0;  
  
# SMTP 인증 사용자 이름  
# 유형: 문자열  
# 기본값: undef  
# $smtp_username = undef;  
  
# SMTP 인증 비밀번호  
# 유형: 문자열  
# 기본값: undef  
# $smtp_password = undef;  
  
######################################################  
#              조회 맵 설정                   #  
######################################################  
  
# 모든 조회 맵의 목록  
# 여기에서 조회 맵을 정의해야 하며  
# 그런 다음 lookup_map_query_order를 설정하여  
# 조회 이름을 참조합니다  
#   
# NOTICE:  
# 모든 조회 맵은 Yaa!가 chroot 감옥에 들어가기 전에 초기화됩니다(있는 경우)  
# 그리고 이메일 처리를 시작하기 전에.  
#   
# NOTICE: 모든 조회 드라이버의 목록을 얻으려면 RUN  
# yaa.pl --list-lookup-map-drivers  
#   
# 유형: 해시의 해시  
# 기본값: 빈 해시(정의된 조회 맵 없음)  
$lookup_maps = {  
    #  
    # !!!경고!!!!  
    #  
    # 드라이버 구성 인수의 전체 목록  
    # RUN yaa.pl --show-lookup-map-doc   
    #  
    # 조회 맵 구성 형식  
    #   
    # 'map_name' => {  
    #    'driver' => 'DRIVER_NAME',  
    #    'driver_param1' => 'value1'.  
    #    'driver_param2' => 'value2',  
    #    'driver_param3' => 'value3',  
    # },  
    # SQL 조회 맵 예  
    #   
    # (사용된 sql 데이터베이스: mysql)  
    # (다른 유형은 perldoc DBD:: 참조)  
    #   
     'my_sql_map' => {  
        'driver' => 'SQL',  
        'sql_dsn' => 'dbi:mysql:database=mail;host=localhost',  
        'sql_username' => "mail_admin",  
        'sql_password' => "mail_admin_password",  
        'sql_select' => "select active,message,subject,charset,forward from autoresponder where address = %m and active='1'",  
    },  
      
    # PCRE 조회 맵 예  
    #   
    # 'my_pcre_map' => {  
    #    'driver' => 'PCRE',  
    #    'file' => "file.pcre",  
    #    'replacement_num' => 0  
    #},  
      
    # 정적 조회 맵 예  
    # 'my_static_map' => {  
    #    'driver' => 'STATIC',  
    #    'result_key1' => 'result_value1',  
    #    'result_key2' => 'result_value2',  
    #    'result' => 'sth'  
    #},  
      
    # LDAP 조회 맵 샘플  
    # 'my_ldap_map' => {  
    #    'driver' => 'LDAP',  
    #    'ldap_host' => 'ldap.example.org',  
    #   
    #    'ldap_bind' => 1,  
    #    'ldap_bind_dn' => "cn=Manager,dc=example,dc=org",  
    #    'ldap_bind_pw' => "secret",  
    #   
    #    'ldap_search_base' => "ou=MyOU,dc=example,dc=org",  
    #    'ldap_search_filter' => "(&(objectClass=rfc822Recipient)(mail=%m)(accountActive=1)",  
    #    'ldap_search_attrs' => ['autoResponseActive', 'autoResponseSubject', 'autoresponseMessage', 'autoResponseCharset', 'autoresponseForward'],  
    #},  
      
    # DB_File 조회 맵 샘플  
    # 'my_dbf_map' => {  
    #    'driver' => 'DB_File',  
    #    'file' => "/path/to/mydb",  
    #},  
      
    # BerkeleyDB 조회 맵 샘플  
    #'my_dbd_map' => {  
    #    'driver' => 'BerkeleyDB',  
    #    'type' => 'Btree',  
    #    'file' => "/path/to/mydb"  
    #},  
};  
  
# 속성별 조회 맵 쿼리 순서  
# 각 자동 응답에 대해 'rewrite_recipient' 및 'rewrite_sender'를 제외하고는  
# 정의된 조회 쿼리 순서가 있어야 합니다  
#   
# 각 항목은 다음과 같이 지정할 수 있습니다:  
# + 문자열   (예: 'domain.tld')  
#   
# 또는  
#   
# lookup_map_name:result_value (예: 'my_pcre_map:result')  
#   
# 조회 맵은 문자열에서 ':' 문자로 인식됩니다.  
#   
# 조회 맵 'lookup_map_name'은 $lookup_maps 구성  
# 매개변수에서 지정되어야 합니다.  
#   
# 유형: 해시의 해시  
# 기본값: 빈 해시(정의된 조회 순서 목록 없음)  
#   
$lookup_map_query_order = {  
        active => [  
                'my_sql_map:active'  
        ],  
        subject => [  
                'my_sql_map:subject'  
        ],  
        message => [  
                'my_sql_map:message'  
        ],  
        charset => [  
               # 'my_sql_map:charset'  
        ],  
        forward => [  
                'my_sql_map:forward'  
        ],  
        rewrite_sender => [  
                #empty  
        ],  
        rewrite_recipient => [  
                #empty  
        ],  
        'local_domains' => [  
                'my_sql_map:local_domains'  
        ],  
};  
######################################################  
#                 기타 설정                     #  
######################################################  
  
# 일부 디렉토리로 chroot합니까?  
# 유형: 문자열  
# 기본값: undef, chroot하지 않음  
# 경고: yaa는 이 기능을 활성화하려면 슈퍼유저로 시작해야 합니다.  
# 이 기능은 데몬 및 단일 메시지 처리 모드에 적용됩니다  
# $chroot = undef;  
  
# 처리 전에 uid/gid를 변경합니까?  
# 유형: 문자열  
# 기본값: undef, uid/gid를 변경하지 않음  
# 경고: yaa는 이 기능을 활성화하려면 슈퍼유저로 시작해야 합니다.  
# 이 기능은 데몬 및 단일 메시지 처리 모드에 적용됩니다  
# $user = undef;  
# $group = undef;  
  
# 메시지를 처리하기 전에 추가 Perl 모듈을 로드합니다.  
# 이 목록의 모듈은 Yaa!가 단일 프로세스 모드에서 메시지를 처리하기 전에 로드되거나  
# 데몬 모드에서 실행될 때 데몬이 됩니다.  
#   
# 이 구성 매개변수는 chroot 감옥에서 실행할 때 매우 유용합니다.  
#   
# 유형: 배열  
# 기본값: 빈 배열(추가 모듈을 로드하지 않음)  
@extra_modules = (  
    # !!!!경고!!!!  
    # chrooted 데몬으로 실행할 때 다음 줄의 주석을 제거하십시오.  
    # 'Net::Server::Mail::ESMTP::PIPELINING',  
      
    # chrooted 상태에서 실행하고 mysql 버전의  
    # SQL 조회 맵을 사용하는 경우 다음 줄의 주석을 제거하십시오.  
    #'DBD::mysql',  
      
    # chrooted 상태에서 실행하고 postgres 버전의  
    # SQL 조회 맵을 사용하는 경우 다음 줄의 주석을 제거하십시오.  
    #'DBD::Pg',  
);  
  
######################################################  
#                 !!!!경고!!!!                    #  
#  YAA가 작동하도록 하려면 다음 줄의 주석을 제거하십시오!  #  
#                 !!!!경고!!!!                    #  
######################################################  
#die "구성 파일을 편집하지 않았습니다, 그죠?:))";  
  
######################################################  
#                 !!!!경고!!!!                    #  
#  다음 줄을 제거하거나 주석 처리하지 마십시오   #  
1;                                                   #  
######################################################  

다음과 같은 내용을 찾아야 합니다

 'my_sql_map' => {  
        'driver' => 'SQL',  
        'sql_dsn' => 'dbi:mysql:database=mail;host=localhost',  
        'sql_username' => "mail_admin",  
        'sql_password' => "mail_admin_password",  
        'sql_select' => "select active,message,subject,charset,forward from autoresponder where address = %m and active='1'", 

자신의 사용자 이름과 비밀번호로 편집하십시오.

다음으로 몇 개의 추가 데이터베이스 항목을 추가해야 합니다.

INSERT INTO `forwardings` ( `source` , `destination` ) VALUES ('[email protected]', '[email protected], [email protected]');
INSERT INTO `transport` ( `domain` , `transport` ) VALUES ('autoreply.domain.com', 'yaa');
INSERT INTO `autoresponder` ( `active` , `message` , `subject` , `charset` , `forward` , `address` , `local_domains` , `tstart` , `tfinish` ) VALUES ('1', 'Message Body', 'Message Subject', '', '', '[email protected]', 'autoreply.domain.com', '0', '0');

또한 tstart/tfinish 값을 채울 수 있으며, 이는 Unix 타임스탬프에서 수행되며 특정 기간 동안 자동 응답기를 활성화할 수 있습니다. 예를 들어 사무실로 돌아온 후 항상 꺼야 하는 사람들에게 좋습니다!

INSERT INTO `autoresponder` ( `active` , `message` , `subject` , `charset` , `forward` , `address` , `local_domains` , `tstart` , `tfinish` ) VALUES ('1', 'Message Body', 'Message Subject', '', '', '[email protected]', 'autoreply.domain.com', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + 14400);

Thunderbird에서 회신의 제목에 대해 매우 이상한 동작을 발견했으므로 구글링하여 문제를 수정하는 작은 패치를 찾았습니다.

email_subject.patch라는 파일을 만듭니다:

--- Autoresponse.pm     2004-08-19 20:35:28.000000000 +0200  
+++ Autoresponse.pm     2005-07-14 13:16:03.000000000 +0200  
@@ -182,7 +182,11 @@  
        push(@headers, "Precedence: bulk");  
  
        # 제목  
-       push(@headers, "Subject: =?" . (($self->{charset}) ? $self->{charset} : $self->{default_charset}) . "?Q?" . encode_qp($subject) . "?=");  
+       #  
+       # 이메일 클라이언트가 이해하지 못하는 이상한 제목을 수정합니다  
+       # (encode_qp의 두 번째 인수는 ""이어야 함)  
+       push(@headers, "Subject: =?" . (($self->{charset}) ? $self->{charset} : $self->{default_charset}) . "?Q?" . encode_qp($subject,"") . "?=");  
  
        push(@headers, "MIME-Version: 1.0"); 

다음으로 패치를 적용합니다:

cd /usr/local/postfix-tools/yaa-0.3/lib/
patch -p0 

이 가이드는 Yaa!의 데몬화된 버전에는 관심이 없으며, 이는 아마도 매우 높은 메일 볼륨에서 더 효율적일 수 있지만, 데몬 버전이 필요한 경우 yaa.conf 파일을 조정하는 것만으로 충분할 것입니다.

Yaa는 특정 시간 동안 동일한 사람에게 응답하지 않는 것과 같은 훌륭한 기능을 가지고 있어 매우 지능적일 수 있습니다. 특히 두 개의 자동 응답 프로그램이 서로에게 응답하여 루프를 생성할 수 있습니다. Yaa에서는 이러한 일이 발생하지 않습니다!

Share: X/Twitter LinkedIn

새 게시물을 받은 편지함에서 받기

스팸은 없습니다. 언제든지 구독 해지 가능합니다.