terça-feira, 30 de agosto de 2011

Postfix e arquivos XML/PDF NF-e

Atualmente tivempos a necessidade de remover os anexos dos e-mails no postfix e salvá-los em um diretório para que um software pudesse utilizá-los para emissão de NF-e.
Procurei na internet e vi que muitas pessoas também tinham essa necessidade. Nessas buscas pela internet eu achei um post do Sr Nick Jeffries (http://tech.jeffri.es/2010/09/automatic-ripping-and-saving-email-attachments-with-postfix/) e partindo desse post adaptei a solução dele à nossa necessidade.

O script original remove os arquivos PDF e descarta a mensagem, o script foi alterado para remover os arquivos PDF/XML e devolver a mensagem pro postfix, afim de evitarmos perdas de e-mails.

Muitas pessoas utilizam scripts no crontab com munpack, o que também é uma boa opção quando seu hardware é mais antigo e não tem tanto desempenho. O desempenho depende do hardware que você utiliza, utilizamos um servidor Dell com 2 processadores Intel(R) Xeon(R) CPU E5504 @ 2.00GHz 4 Cores, com 16GB RAM, HD SAS 500GB em raid 1.
Aparentemente a utilização do script dentro do postfix como um "filtro" não fez nem cócegas no servidor.

A solução implantada aqui utliza: postfix (www.postfix.org) e ripmime (http://www.pldaniels.com/ripmime/).

Nesse post estamos nos baseando que já há um postfix instalado, configurado e funcionando.
Utilizamos o Ubuntu 10.x mas esse filtro funciona em qualquer distribuição, basta ajustá-lo.

A solução segue o original do Jeffries e está dividida nos passos:
  • Instalação do ripMIME
  • Configurando o postfix para executar um filtro na chegada dos e-mails (incoming mail)
  • Criando o script de filtro
  • Ajustes finais

Instalação do ripMIME

Primeiro de tudo, nós precisamos instalar o ripMIME, que é um utilitário para extrair o anexo de um e-mail e salvá-lo em algum lugar. Vamos precisar efetuar o download, compilação e instalação, uma coisa bem simples e fácil.

Antes de mais nada você precisa do compilador gcc instalado em seu sistema, caso você não o tenha instale-o. Para instalar o gcc utilize o aptitude ou o yum para instalar (aptitude install gcc / yum install gcc).
Aconselho criar um diretório e baixar o ripMIME para esse diretório.

No prompt do servidor digite:


mkdir temp
cd temp
wget http://www.pldaniels.com/ripmime/ripmime-1.4.0.9.tar.gz
tar zxvf ripmime-1.4.0.9.tar.gz
rm -f rip*.gz
cd ripmime-1.4.0.9/
make
sudo make install


Por padrão o ripmime se instala em /usr/local/bin , você pode alterar o local de instalação dele mas vamos utilizar o padrão.

Configurando o postfix para executar um filtro na chegada dos e-mails (incoming mail)

Vamos criar um script para executar com o postfix, o postfix vai "chamar" o script para verificar o e-mail que chegou, esse script vai fazer o papel de filtro e devolver a mensagem pro MTA.

O que precisamos no momento é adicionar as linhas abaixo no final "master.cf" do postfix (/etc/postfix/master.cf)


# Inserido por fulano : fulano@mail.com data: dd/mm/aaaa
# Begin
saveattachment unix - n n - 10 pipe
flags=Rq user=mail argv=/usr/bin/saveattachment -f ${sender} -- ${recipient}
# End

Essa linha diz ao postfix que o filtro chamado "saveattachment" é um script unix. Os e-mails de entrada (incoming) que utilizam esse filtro serão desviados para o script que está localizado em "/usr/bin/saveattachment"

Utilizamos esse filtro somente para os e-mails que chegam (incoming), procure a linha abaixo e adicione essa linha também ao "master.cf":

#
smtp inet n - - - - smtpd
#alterado por fulano: fulano@mail.com data DD/MM/AAAA
# Begin
-o content_filter=saveattachment:dummy
# End

Utilizei o usuário "mail" para execução do script, será com o id/gid desse usuário que os arquivos serão salvos, logo o usuário deverá ter permissão rwx no diretório que utilizaremos para deixar os arquivos extraídos.


Criando o script de filtro

O script utilizado é derivado do exemplo existente na documentação do Postfix (http://www.postfix.org/FILTER_README.html#simple_filter) .
O script salva os anexos e copia qualquer pdf/xml para um diretório, renomeando o anexo.
O script pode ser alterado facilmente ajustado conforme a necessidade.

--- Inicio do arquivo ---
#!/bin/bash

# Version 1.0 of script to save mail attachments
# Requires ripmime
# Original script http://tech.jeffri.es/wp-content/uploads/2010/09/saveattachment.txt
# Original script by Nick Jeffries
# Adjusted by Murilo Vitorino http;//mgvitorino.blogspot.com/


# alterar variavel "INSPECT_DIR" para o diretorio temporario que sera utilizado para extrair o arquivo
INSPECT_DIR=/maildir/temp/
# alterar variavel "TARGET_DIR" para diretorio onde serao colocados arquivos pdf/xml
TARGET_DIR=/maildir/server/
SN="saveattachment:"

# linha para reenvio da msg ao postfix
SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here.


# Exit codes from <sysexits.h>

EX_TEMPFAIL=75
EX_UNAVAILABLE=69

# Clean up when done or when aborting.

trap "rm -f in.$$ *textfile*" 0 1 2 3 15

echo "$SN Starting scan of incoming email"

# Start processing.
cd $INSPECT_DIR || {
echo "$SN $INSPECT_DIR does not exist"; exit $EX_TEMPFAIL; }

cat >in.$$ || {
echo "$SN: Cannot save mail to file"; exit $EX_TEMPFAIL; }


# Now invoke ripmime to process the temporary file

echo "$SN Invoking ripmime"

/usr/local/bin/ripmime -v --prefix -i in.$$ || {
echo "$SN Ripmime failed"; exit $EX_TEMPFAIL; }

NUM_SOURCE_FILES=`ls -1 *.pdf | wc -l`

# Adicionado ao script original para filtrar arquivos xml
#
NUM_SOURCE_FILES1=`ls -1 *.xml | wc -l`
#
#

if [ $NUM_SOURCE_FILES -gt 0 ]; then
for f in *.pdf
do
TARGET_FILE=${TARGET_DIR}$$_$f

echo "$SN Setting perms and copying $f to $TARGET_FILE"
chmod 775 $f
mv $f $TARGET_FILE
done
else
echo "$SN No PDF files to copy"
fi

# adicionado para pegar arquivos xml de nf-e
#

if [ $NUM_SOURCE_FILES1 -gt 0 ]; then
for f in *.xml
do
TARGET_FILE=${TARGET_DIR}$$_$f

echo "$SN Setting perms and copying $f to $TARGET_FILE"
chmod 775 $f
mv $f $TARGET_FILE
done
else
echo "$SN No XML files to copy"
fi


#
#

# linha para reinject da msg no postfix
$SENDMAIL "$@" <in.$$

exit $?

--- Fim do arquivo ---


Ajustes Finais

Precisamos criar os diretórios para que o script funcione:

sudo chmod 755 /usr/bin/saveattachment
sudo mkdir -p /maildir/temp
sudo mkdir /maildir/server
sudo chown -R postfix: /maildir
sudo chmod 770 /maildir/temp
sudo chmod 770/maildir/server
sudo chown mail:postfix /maildir/server
sudo chown mail:postfix /maildir/temp

Para testar o script você pode criar um arquivo de mensagem com xml/pdf, enviar via telnet ou através do próprio script saveattachment. Primeiro vamos criar uma mensagem em formato mime com um pequeno xml dentro:


vi ~/mensagem
--- Inicio do arquivo---
Content-Type: multipart/mixed; boundary=00032555b4663d720b04ababfe2e

--00032555b4663d720b04ababfe2e
Content-Type: multipart/alternative; boundary=00032555b4663d720304ababfe2c

--00032555b4663d720304ababfe2c
Content-Type: text/plain; charset=ISO-8859-1

--
Atenciosamente,
--00032555b4663d720304ababfe2c
Content-Type: text/html; charset=ISO-8859-1

--00032555b4663d720304ababfe2c--
--00032555b4663d720b04ababfe2e
Content-Type: text/xml; charset=US-ASCII; name="teste.xml"
Content-Disposition: attachment; filename="teste.xml"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_grxzndh50

PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8YXZpc28+DQo8cGFyYT5QYXJhIFhNTCAiMDEvMDQvMjAw
MCI8L3BhcmE+DQo8ZGU+VGVzdGU8L2RlPg0KPGNhYmVjYWxobz5MZW1icmUtc2U8L2NhYmVjYWxo
bz4NCjxjb3Jwbz5BbWFuaGEgdm9jZSB0ZW0gcHJvdmEgZGUgbWF0ZW1hdGljYTwvY29ycG8+DQo8
L2F2aXNvPiANCg==
--00032555b4663d720b04ababfe2e--

--- Fim do Arquivo ---


Agora vamos usar o script para enviar essa mensagem:

/usr/bin/saveattachment -f remetente@dominio.com -- destinatario@dominio.com < mensagem

Verifique o diretorio escolhido para os arquivos XML onde deve conter um arquivo xml com o nome $idmsg_teste.xml .

Qualquer dúvida, estou à disposição.

Nenhum comentário:

Postar um comentário