Autoresponders · 14 min read · Jan 04, 2026

Autoresponders para acompanhar Usuários Virtuais e Domínios com Postfix, Courier e MySQL

Autoresponders para acompanhar Usuários Virtuais e Domínios com Postfix, Courier e MySQL

Este guia foca em fazer o Yaa! (Yet Another Autoresponder!) funcionar com Debian Sarge e o tutorial de usuários virtuais no Postfix (veja https://www.howtoforge.com/virtual_postfix_mysql_quota_courier).

A primeira coisa a entender sobre o guia é que ele usa o Agente de Entrega Virtual (VDA) e, como resultado, qualquer um dos autoresponders que você poderia usar passando-os para um pipe via um arquivo .forward simplesmente não funcionará, pois o VDA não suporta expansões .forward. Essa limitação pode ser superada via entrega Procmail/Maildrop, mas isso é bagunçado e mais lento, especialmente para sistemas de e-mail que são muito utilizados. A resposta simples é Yaa!

Vamos baixar o Yaa e começar a festa:

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

Em seguida, precisamos obter os módulos Perl necessários para fazer o Yaa funcionar. O Yaa funciona em ambos os modos de daemon, no entanto, neste guia, eu só vou me preocupar com o modo não daemonizado do programa.

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

Vamos configurar a estrutura do banco de dados para que o Yaa funcione:

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;

Em seguida, queremos configurar o Postfix para invocar o Yaa! via um transporte, então precisamos editar /etc/postfix/master.cf para adicionar o seguinte:

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

Vamos reiniciar o Postfix para habilitar as mudanças:

/etc/init.d/postfix restart

Finalmente, precisamos configurar o Yaa! Para facilitar as coisas, eu forneci meu yaa.conf

######################################################  
#                 !!!!WARNING!!!!                    #  
#  NÃO REMOVA OU COMENTE A LINHA SEGUINTE            #  
use strict;                                          #  
######################################################  
  
# AVISO:  
# Se você está tendo problemas para executar yaa.pl e não  
# tem certeza do que está errado, defina a variável de ambiente  
#  
#                   YAA_DEBUG  
#  
# e execute yaa.pl novamente com os mesmos argumentos/arquivo de configuração.  
#  
# A saída de depuração do Yaa será escrita no stderr se executado em modo de  
# processamento de mensagem única ou em modo daemon com $daemon_background = 0.  
#   
# Se você estiver executando em modo daemon com $daemon_background = 1, mensagens de depuração  
# serão enviadas para o subsistema de logger se estiver habilitado.  
#  
# exemplo para csh:  
# setenv YAA_DEBUG 1  
#  
# exemplo para sh/ksh/bash:  
# export YAA_DEBUG=1  
#  
  
# NOTAS GERAIS  
#   
# trecho retirado do arquivo de configuração do excelente projeto opensource  
# chamado amavisd-new   
# por Mark Martinec .  
#   
#  Este arquivo é um código Perl normal, interpretado pelo próprio Perl.  
#  - certifique-se de que este arquivo (ou diretório onde reside) NÃO É GRAVÁVEL  
#    por meros mortais, caso contrário, representa um grave risco de segurança!  
#  - para valores que são interpretados como booleanos, é recomendado  
#    usar 1 para verdadeiro, e 0 ou undef ou '' para falso.  
#  - A sintaxe Perl se aplica. Notavelmente: strings em "" podem incluir variáveis  
#    (que começam com $ ou @); para incluir caracteres @ e $ em strings entre aspas duplas,  
#    preceda-os com uma barra invertida; em strings entre aspas simples  
#    o $ e @ perdem seu significado especial, então geralmente é mais fácil usar  
#    strings entre aspas simples. Ainda assim, em ambos os casos a barra invertida precisa ser duplicada.  
  
  
######################################################  
#           CONFIGURAÇÕES DO SUBSISTEMA DE LOGGING     #  
######################################################  
  
# habilitar logging?  
# tipo: booleano  
# padrão: 1  
# $logging = 1;  
  
# habilitar logging para syslog?  
# tipo: booleano  
# padrão: 1  
$log_syslog = 1;  
  
# instalação de logging syslog  
# tipo: string  
# padrão: "mail"  
# esta configuração se aplica apenas quando o logging para syslog está habilitado  
# $log_syslog_facility = "mail";  
  
# prioridade de logging syslog  
# tipo: string  
# padrão: "info"  
# esta configuração se aplica apenas quando o logging para syslog está habilitado  
# $log_syslog_priority = "info";  
  
# log para arquivo de texto?  
# tipo: booleano  
# padrão: 0  
#$log_file = 1;  
  
# nome do arquivo de log  
# tipo: string  
# padrão: undef  
# esta configuração se aplica apenas quando o logging para arquivo está habilitado  
#$log_file_filename = "/var/log/yaa.log";  
  
# log para stderr?  
# tipo: booleano  
# padrão: 0  
# !!!! AVISO !!!!  
# quando a depuração do yaa está ativada (variável de ambiente YAA_DEBUG está definida),  
# a saída STDERR é mapeada para o subsistema de logger e nada aparece  
# no verdadeiro stderr, então certifique-se de configurar o logging baseado em syslog ou arquivo.  
# !!!! AVISO !!!!  
# $log_stderr = 0;  
  
# formato de tempo do log ao registrar em arquivo  
# tipo: string  
# padrão: "[%a, %b %e %T %Y]: "  
# veja strftime(3) para mais detalhes  
# $log_time_format = undef;  
  
  
######################################################  
#               CONFIGURAÇÕES DO MODO DAEMON          #  
######################################################  
  
# executar como daemon?  
# tipo: booleano  
# padrão: 0, não executar como daemon  
# esta configuração habilita a operação em modo daemon.  
# $daemon = 1;  
  
$daemon = 0;  
$daemon_lockfile = "/tmp/yaa.lock";  
$daemon_pidfile = "/tmp/yaa.pid";  
$daemon_tcpserver_loglevel = 4;  
  
# fork para o background ao executar como daemon?  
# padrão: 1  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_background = 1;  
  
# arquivo de bloqueio do daemon  
# tipo: string  
# padrão: "/var/lock/yaa.lock"  
# esta configuração se aplica apenas quando operando em modo daemon  
# AVISO: se executando em chroot jail, esta opção deve ser  
# definida em relação ao diretório chroot  
# $daemon_lockfile = "/tmp/yaa.lock";  
  
# arquivo pid do daemon  
# tipo: string  
# padrão: "/var/run/yaa.lock"  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_pidfile = "/tmp/yaa.pid";  
  
# número mínimo de processos filhos do yaa  
# tipo: inteiro  
# padrão: 2  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_min_servers = 2;  
  
# número máximo de processos filhos do yaa  
# tipo: inteiro  
# padrão: 3  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_max_servers = 3;  
  
# número mínimo de processos filhos do yaa em espera  
# tipo: inteiro  
# padrão: 1  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_min_spare_servers = 0;  
  
# número máximo de processos filhos do yaa em espera  
# tipo: inteiro  
# padrão: 1  
# esta configuração se aplica apenas quando operando em modo daemon  
#$daemon_max_spare_servers = 1;  
  
# protocolo de comunicação do daemon  
# tipo: string  
# protocolo que seu MTA usa para comunicação com yaa  
#  
# AVISO: para possíveis valores para este parâmetro de configuração, EXECUTE  
# yaa.pl --list-transport-protocols  
#  
# padrão: "SMTP"  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_protocol = "LMTP";  
  
# porta de escuta tcp ou socket de domínio unix no qual o yaa deve escutar  
# tipo: inteiro/string  
# padrão: 40000  
# para especificar socket de domínio unix, defina o valor como: '/path/to/socket|unix'  
#  
# veja também: perldoc Net::Server::Proto  
#  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_listen_port = 40000;  
  
# nome do host ao qual o yaa deve se vincular.  
# tipo: string  
# padrão: "localhost"  
# esta configuração se aplica apenas quando operando em modo daemon  
# $daemon_listen_host = "127.0.0.1";  
  
# nível de log do tcpserver do daemon (Net::Server)  
# tipo: inteiro  
# padrão: 0  
# 'O' => desabilitar logging  
# 0 => 'err'  
# 1 => 'warning'  
# 2 => 'notice'  
# 3 => 'info'  
# 4 => 'debug'  
$daemon_tcpserver_loglevel = 4;  
  
  
######################################################  
#               CONFIGURAÇÕES DO OBJETO YAA           #  
######################################################  
  
# diretório usado para armazenar o banco de dados de tempo de envio da mensagem de resposta automática.  
# tipo: string  
# padrão: "/tmp"  
# !!!! AVISO !!!!  
#   
#   -  se você estiver executando yaa em chroot (veja a variável de configuração $chroot),  
#      então você precisa definir esta variável para um valor RELATIVO ao diretório chroot  
#   
#   - o diretório deve ser gravável para uid/gid que o yaa usa para processamento de mensagens  
#     veja também as variáveis $user e $group  
#   
# !!!! AVISO !!!!  
# $db_dir = "/db";  
  
# tempo em segundos entre duas respostas automáticas que serão enviadas para o  
# mesmo remetente de mensagem do destinatário que tem o autoresponder  
# ativado.  
#   
# !!!! AVISO !!!!  
#   
# Para fins de teste, defina como -1 (desativar verificação de tempo),   
# MAS NÃO DEFINA ESTE VALOR MENOR QUE 3600 (1 hora) NO  
# SISTEMA DE PRODUÇÃO !!!!  
#   
# !!!! AVISO !!!!  
# tipo: inteiro  
# padrão: 7200  
# $duration_interval = 24 * 60 * 60;  
$duration_interval = "-1";  
  
######################################################  
#             CONFIGURAÇÕES DE RESPOSTA AUTOMÁTICA     #  
######################################################  
  
# método usado para enviar respostas automáticas e encaminhar mensagens  
# tipo: string  
# valores possíveis: "smtp", "sendmail"  
# - "smtp" usa servidor smtp para enviar e-mail  
# - "sendmail" invoca o binário sendmail para enviar e-mail  
#  
# !!!!AVISO!!!!: coisas estranhas acontecem ao usar o método de envio sendmail  
# e executando em modo daemon!  
#  
# padrão: "smtp"  
# $mail_sending_method = "smtp";  
  
# caminho do programa sendmail  
# tipo string  
# padrão: pesquisado automaticamente na variável de ambiente $PATH;  
# undef se não encontrado no $PATH.  
#$sendmail_path = undef;  
  
# configuração do servidor SMTP  
# tipo: string  
#  
# veja também perldoc Net::SMTP  
#  
# padrão: localhost  
# $smtp_server = "localhost";  
  
# Usar autenticação SMTP?  
# tipo: booleano  
# padrão: 0  
# $smtp_auth = 0;  
  
# nome de usuário de autenticação SMTP  
# tipo: string  
# padrão: undef  
# $smtp_username = undef;  
  
# senha de autenticação SMTP  
# tipo: string  
# padrão: undef  
# $smtp_password = undef;  
  
######################################################  
#              CONFIGURAÇÕES DO MAPA DE BUSCA          #  
######################################################  
  
# Lista de TODOS os mapas de busca  
# Você precisa definir mapas de busca aqui e  
# então definir lookup_map_query_order, onde você faz referência ao  
# nome da busca  
#   
# AVISO:  
# Todos os mapas de busca são inicializados ANTES do Yaa! entrar na jaula chroot (se houver)  
# e ANTES de começar a processar e-mails.  
#   
# AVISO: Para obter a lista de todos os drivers de busca, EXECUTE  
# yaa.pl --list-lookup-map-drivers  
#   
# tipo: hash de hashes  
# padrão: hash vazio (nenhum mapa de busca definido)  
$lookup_maps = {  
    #  
    # !!!AVISO!!!!  
    #  
    # PARA LISTA COMPLETA DOS ARGUMENTOS DE CONFIGURAÇÃO DO DRIVER  
    # EXECUTE yaa.pl --show-lookup-map-doc   
    #  
    # Formato de configuração do mapa de busca  
    #   
    # 'map_name' => {  
    #    'driver' => 'DRIVER_NAME',  
    #    'driver_param1' => 'value1'.  
    #    'driver_param2' => 'value2',  
    #    'driver_param3' => 'value3',  
    # },  
    # Exemplo de mapa de busca SQL  
    #  
    # (banco de dados usado: mysql)  
    # (para outros tipos veja 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'",  
    },  
      
    # Exemplo de mapa de busca PCRE  
    #  
    # 'my_pcre_map' => {  
    #    'driver' => 'PCRE',  
    #    'file' => "file.pcre",  
    #    'replacement_num' => 0  
    #},  
      
    # Exemplo de mapa de busca ESTÁTICO  
    # 'my_static_map' => {  
    #    'driver' => 'STATIC',  
    #    'result_key1' => 'result_value1',  
    #    'result_key2' => 'result_value2',  
    #    'result' => 'sth'  
    #},  
      
    # Exemplo de mapa de busca 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'],  
    #},  
      
    # Exemplo de mapa de busca DB_File  
    # 'my_dbf_map' => {  
    #    'driver' => 'DB_File',  
    #    'file' => "/path/to/mydb",  
    #},  
      
    # Exemplo de mapa de busca BerkeleyDB  
    #'my_dbd_map' => {  
    #    'driver' => 'BerkeleyDB',  
    #    'type' => 'Btree',  
    #    'file' => "/path/to/mydb"  
    #},  
};  
  
# ordem da consulta do mapa de busca por atributo  
# para cada resposta automática, exceto 'rewrite_recipient' e 'rewrite_sender' deve  
# ser definida a ordem da consulta de busca  
#   
# Cada item pode ser especificado como:  
# + string   (exemplo: 'domain.tld')  
#   
# OU  
#   
# lookup_map_name:result_value (exemplo: 'my_pcre_map:result')  
#  
# O mapa de busca é reconhecido pelo caractere ':' na string.  
#  
# O 'lookup_map_name' DEVE SER especificado na configuração $lookup_maps  
# no parâmetro de configuração yaa.conf  
#  
# tipo: hash de hashes  
# padrão: hash vazio (nenhuma lista de ordem de busca definida)  
#  
#  
$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'  
        ],  
};  
  
######################################################  
#                 OUTRAS CONFIGURAÇÕES                #  
######################################################  
  
# chroot para algum diretório?  
# tipo: string  
# padrão: undef, não fazer chroot  
# Aviso: yaa deve ser iniciado como superusuário para habilitar este recurso.  
# isso se aplica ao modo daemon e ao modo de processamento de mensagem única  
# $chroot = undef;  
  
# mudar uid/gid antes do processamento?  
# tipo: string  
# padrão: undef, não mudar uid/gid  
# Aviso: yaa deve ser iniciado como superusuário para habilitar este recurso.  
# isso se aplica ao modo daemon e ao modo de processamento de mensagem única  
# $user = undef;  
# $group = undef;  
  
# Carregar módulos Perl adicionais antes de processar qualquer mensagem  
# Os módulos nesta lista serão carregados antes que o Yaa! processe qualquer  
# mensagem em modo de processo único ou se torne um daemon, ao executar  
# em modo daemon.  
#   
# Este parâmetro de configuração é muito útil quando  
# ao executar em chroot jail  
#   
# tipo: array  
# padrão: array vazio (não carregar módulos adicionais)  
@extra_modules = (  
    # !!!!AVISO!!!!  
    # quando como daemon chrooted, descomente a linha a seguir  
    # 'Net::Server::Mail::ESMTP::PIPELINING',  
      
    # se executando chrooted, e usando a versão mysql  
    # do mapa de busca SQL, descomente a linha a seguir  
    #'DBD::mysql',  
      
    # se executando chrooted, e usando a versão postgres  
    # do mapa de busca SQL, descomente a linha a seguir  
    #'DBD::Pg',  
);  
  
######################################################  
#                 !!!!AVISO!!!!                      #  
#  COMENTE A LINHA SEGUINTE PARA FAZER O YAA FUNCIONAR!  #  
#                 !!!!AVISO!!!!                      #  
######################################################  
#die "Você não editou o arquivo de configuração, não é?:))";  
  
######################################################  
#                 !!!!AVISO!!!!                      #  
#  NÃO REMOVA OU COMENTE A LINHA SEGUINTE            #  
1;                                                   #  
######################################################  

Você precisará encontrar

 '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'",  

e editar para seu próprio nome de usuário e senha.

Em seguida, precisamos adicionar algumas entradas adicionais ao banco de dados.

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', 'Mensagem Corpo', 'Mensagem Assunto', '', '', '[email protected]', 'autoreply.domain.com', '0', '0');

Além disso, você pode preencher os valores tstart/tfinish, que são feitos em timestamp Unix e permitem que você ative o autoresponder por um período de tempo específico - ótimo para pessoas que sempre esquecem de desligá-los depois que retornam ao escritório, por exemplo!

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

Sob o Thunderbird, notei um comportamento muito peculiar em relação ao Assunto da resposta, então eu pesquisei e encontrei um pequeno patch para corrigir o problema.

Crie um arquivo chamado 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");  
  
        # Assunto  
-       push(@headers, "Subject: =?" . (($self->{charset}) ? $self->{charset} : $self->{default_charset}) . "?Q?" . encode_qp($subject) . "?=");  
+       #  
+       # Corrige os assuntos estranhos que os clientes de e-mail não entendem  
+       # (o segundo argumento em encode_qp deve ser "")  
+       push(@headers, "Subject: =?" . (($self->{charset}) ? $self->{charset} : $self->{default_charset}) . "?Q?" . encode_qp($subject,"") . "?=");  
  
        push(@headers, "MIME-Version: 1.0"); 

Em seguida, aplicamos o patch:

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

Este guia não se preocupa com a versão daemonizada do Yaa! que provavelmente seria mais eficiente em volumes extremamente altos de e-mail, mas deve ser apenas uma questão de ajustar o arquivo yaa.conf se a versão daemon for necessária.

O Yaa tem alguns ótimos recursos, como não responder a mesma pessoa dentro de um determinado período de tempo, então pode ser muito inteligente, especialmente porque você pode ter dois programas de resposta automática respondendo um ao outro e criando um loop. Isso não acontece com o Yaa!

Share: X/Twitter LinkedIn

Receba novas postagens na sua caixa de entrada

Sem spam. Cancele a assinatura a qualquer momento.