Recentemente tive um problema curioso ao utilizar a ferramenta de envio de email da Amazon, o Amazon SES, e gostaria de compartilhar a solução com vocês porque as referências que usei para a solução estavam todas muito espalhadas. Então vamos lá!
Em um dos projeto em que estou trabalhando ultimamente, resolvemos mudar o envio do email para utilizar um serviço mais confiável do que o nosso próprio servidor e, por diversos fatores que não cabem nesse post, escolhemos o Amazon SES. Para fazer a integração com o Django, utilizamos o projeto Django-SES. Tudo funcionou muito bem nos testes locais e no ambiente de staging. Mas, quando testamos em produção, tivemos um erro relativamente estranho:
BotoServerError: BotoServerError: 400 Bad Request
<ErrorResponse xmlns="http://ses.amazonaws. com/doc/2010-12-01/">
<Error>
<Type>Sender</Type>
<Code>RequestExpired</Code>
<Message>Request timestamp: Fri, 10 May 2013 14:54:17 GMT expired. It must be within 300 secs/ of server time.</Message>
</Error>
<RequestId>123123123123123123123123</RequestId>
</ErrorResponse>
Curiosamente, esse erro acontecia somente somente em algumas das máquinas de produção. Então, rapidamente pudemos deduzir que o problema era causado por algum erro de configuração de máquinas específicas. Pesquisando nos fóruns da Amazon, achamos esse post que nos deu um caminho a seguir e pudemos entendê-lo melhor ao ler a documentação da Amazon na parte em que fala de autenticação (Programming Guide > About Requests and Responses > Request Authentication > HMAC-SHA1 Signatures). O que estava bloqueando o envio de email era que o parâmetro de timestamp, que é necessário para a autenticação, estava sendo formado de maneira errada ou com um valor inválido.
Utilizando o comando date, pudemos ver que de fato havia algo estranho já que o máquina estava 8 minutos no futuro! Óbvio que o tempo que estava gerando era invalidado pelo Amazon SES já que ele ainda nem aconteceu. Ainda não descobri o porquê disso ter acontecido, mas suspeito que tenha sido algum erro de configuração inicial da máquina. Para resolver o problema, bastou sincronizar o horário do computador executando o comando:
sudo ntpdate br.pool.ntp.org br.pool.ntp.org br.pool.ntp.org
Para evitar problemas futuros em outras máquinas, achei conveniente adicionar esse comando como último comando no processo de deploy feito pelo Fabric e também criar uma tarefa no cron que faz essa atualização regularmente. Não sei se é exagero, mas como ainda não identifiquei a causa do problema, é melhor prevenir do que remediar.
O interessante desse processo foi descobrir como o Linux resolve a sincronia de data e hora descobrindo o comando ntpdate. E, além disso, acabei descobrindo mais um dos quase infinitos protocolos que eu não conhecia que, no caso, é o Network Time Protocol (NTP), que é um dos protocolos mais antigos existentes e é responsável por viabilizar a sincronia entre relógios de máquinas diferentes (inclusive levando em conta a latência da rede).
Como eu disse, a ideia desse post foi somente compartilhar o problema e consolidar a solução para consulta futura ou para ajudar algum desaventurado que tenha esse mesmo problema. Para se aprofundar mais no tema de configuração de horário da máquina, aconselho esse excelente post do Flávio Torres. Até a próxima!