메일 서버 · 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-toolswget http://frost.ath.cx/software/yaa/dist/yaa-0.3.tar.bz2tar 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-perlYaa가 작동하도록 데이터베이스 구조를 설정합시다:
mysql -uroot -puse 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에서는 이러한 일이 발생하지 않습니다!
새 게시물을 받은 편지함에서 받기
스팸은 없습니다. 언제든지 구독 해지 가능합니다.