Tutorial de Python: como o ImgPage permite o upload de fotos de 25 MB para o S3 e arquivos na nuvem usando apenas um e-mail
Este post foi escrito por Paul Finn. Paul é um desenvolvedor Python de Portsmouth, NH, dono de empresa (http://route3software.com/) e entusiasta de cerveja (https://hoppypress.com/beer-art). Acompanhe seu blog em http://www.pfinn.net/, seus tweets em @paulfinn e seu código em https://github.com/pfinn
Meus projetos de desenvolvimento web favoritos sempre envolvem a criação de uma ferramenta em torno de uma API recém-descoberta e já sou grande fã do Mailgun há um tempo. A API deles não apenas lida com uma das coisas mais difíceis de se acertar, o processamento de e-mails, mas faz isso muito bem. É um ótimo exemplo de como uma API moderna e amigável para a equipe de desenvolvimento deve ser: é RESTful, resolve um problema real, tem uma documentação sólida e é rápida para começar a usar.
Criando um aplicativo de hospedagem e upload de imagem fácil de usar
Recorri ao Mailgun há algumas semanas quando decidi criar um host de imagens rápido que pudesse receber imagens por e-mail e não dependesse de um processo tradicional de upload do lado do cliente. Muitos dos smartphones atuais não têm suporte nativo para uploads no navegador, então pode ser um pouco complicado encontrar uma maneira de tirar as fotos do seu telefone e compartilhá-las apenas com um link (e ignorando qualquer rede social).
Criei o ImgPage (“Image Page”) para resolver esse problema: basta anexar uma foto (ou algumas) a um e-mail e enviar para inbox@imgpage.com. Aguarde alguns segundos e você receberá uma resposta por e-mail do ImgPage com um link exclusivo para uma página limpa e sem poluição visual apresentando apenas a(s) sua(s) imagem(ns), como abaixo.
Abaixo, mostrarei um exemplo simplificado de código sobre como o ImgPage usa o Mailgun para fazer o upload dessas imagens para a nuvem.
Processando e-mails recebidos usando a API Routes do Mailgun
Após criar um repositório git para o ImgPage, a próxima etapa foi criar o inbox@imgpage.com rota dentro do Mailgun. Uma rota é o que o Mailgun chama de lógica que diz ao seu sistema o que fazer com cada e-mail de entrada que recebe. Para o ImgPage, configurei o Mailgun para processar cada e-mail recebido em inbox@imgpage.com e fazer um POST dos detalhes para o meu servidor.
requests.post("https://api.mailgun.net/v2/routes",
auth=("api", os.environ.get("MAILGUN_KEY", "your-api-key"))),
data=MultiDict([("description", "ImgPage Inbox Processing"),
("expression", "match_recipient('inbox@imgpage.com')"),
("action", "forward('http://imgpage.com/mailgun-endpoint/')"),
("action", "stop()")
]))
Um truque legal sobre o Mailgun: você não está limitado apenas a corresponder aos destinatários de e-mail. Você pode corresponder aos cabeçalhos de e-mail, como a linha de assunto, e também usar expressões regulares. Você pode criar rotas de forma programática, conforme demonstrado acima, ou pode criar rotas usando o painel do Mailgun após fazer login. Aqui estão as especificações completas da API de processamento de e-mails de entrada.
Quando se trata dos anexos, o Mailgun faz o trabalho pesado por nós e fará o POST das informações que precisamos sobre todo e qualquer anexo de até 25 MB (na verdade, o tamanho máximo é 1 ou 2 KB menor que 25 MB, já que o espaço precisa ser reservado para cabeçalhos de e-mail). Neste exemplo simplificado, estou analisando a solicitação para verificar se há pelo menos um anexo e se o anexo possui uma extensão de arquivo de foto comum que estamos aguardando (caso contrário, retorna um erro HTTP 415).
@app.route(‘/mailgun-endpoint’, methods=[‘POST’]) def mailgun_endpoint(): if(len(request.files) > 0): for attachment in request.files.values(): file_name, file_extension = os.path.splitext(attachment.filename) if file_extension.lower() not in [‘.jpg’, ‘.gif’, ‘.png’, ‘.bmp’]: abort(415) #Tipo de mídia não suportado
@app.route('/mailgun-endpoint', methods=['POST'])
def mailgun_endpoint():
if(len(request.files) > 0):
for attachment in request.files.values():
file_name, file_extension = os.path.splitext(attachment.filename)
if file_extension.lower() not in ['.jpg', '.gif', '.png', '.bmp']:
abort(415) #Unsupported Media Type
Fazendo upload de fotos para o Rackspace Cloud Files & Amazon S3
Agora eu tinha algumas opções de armazenamento em nuvem confiável, sendo a mais popular o Amazon S3. Estou sempre disposto a experimentar um serviço novo e aprender uma nova API, e decidi dar uma chance ao Rackspace Cloud Files também (a Rackspace adquiriu o Mailgun recentemente, então, com o tempo, eles provavelmente criarão algumas integrações nativas). Eu tinha muita experiência usando o S3 e fiquei agradavelmente surpreso com a facilidade de começar a usar o Cloud Files. Os conceitos básicos, coisas como contêineres e buckets, são bem semelhantes entre os dois serviços.
image_attachment.public_uri()
'http://c1234.cdn.cloudfiles.rackspacecloud.com/6a8f43...ab3cb7.jpg'
No caso do ImgPage, é importante que tudo dentro do contêiner de imagens seja acessível publicamente com um URL exclusivo. Após o upload, você pode solicitar o URI público a partir do Cloud Files.
Como você pode ver, o Cloud Files é fácil e simples de se trabalhar. Se você quiser continuar com o Amazon S3, veja como você poderia lidar com o upload dos anexos usando a biblioteca Python boto.
from boto.s3.key import Key
from boto.s3.connection import S3Connection
conn = S3Connection(my-access-key, my-secret-key)
bucket = conn.get_bucket('images')
key = Key(bucket)
key = ('%s%s') % (str(uuid.uuid4()), file_extension)
key.set_contents_from_filename(attachment.filename)
(Quando você terminar de lidar com o POST, o Mailgun espera ver uma resposta HTTP 200 OK. Caso contrário, essa ação será registrada como um erro nos seus logs do Mailgun.)
Conclusão
O roteamento de e-mails recebidos e o processamento de anexos são muito fáceis com o Mailgun. Consegui combinar a correspondência de destinatários e as ações de encaminhamento do Mailgun com o Cloud Files e o Amazon S3 para criar o ImgPage. Sem ter o Mailgun, eu provavelmente não teria abordado este projeto em primeiro lugar devido às dificuldades de processar e-mails de entrada. O Mailgun tem a minha aprovação total por resolver um problema difícil e criar uma API estável e bem documentada para acompanhá-lo.