unsubscribe_html

Dependências

Este script em Python tem as seguintes dependências:

  • imapclient: biblioteca para acesso à caixa de entrada do Outlook via IMAP
  • email: biblioteca padrão do Python para trabalhar com e-mails
  • os: biblioteca padrão do Python para interagir com o sistema operacional
  • dotenv: biblioteca para carregar variáveis de ambiente a partir de um arquivo .env
  • bs4 (BeautifulSoup): biblioteca para extrair informações de páginas HTML
  • urllib: biblioteca padrão do Python para manipulação de URLs

Variáveis de Ambiente

Este script usa as seguintes variáveis de ambiente:

  • EMAIL_ADDRESS: endereço de e-mail da conta do Outlook a ser usada
  • EMAIL_PASSWORD: senha da conta do Outlook a ser usada
  • IMAP_SERVER: endereço do servidor IMAP do Outlook
  • IMAP_SSL: indica se deve ser usada uma conexão SSL/TLS para se conectar ao servidor IMAP (True) ou não (False).
  • UNSEEN (opcional): indica se devem ser buscados apenas e-mails não lidos (True) ou todos os e-mails (False). Se esta variável não for definida ou se seu valor não for "True", serão buscados todos os e-mails.
  • FOLDERS_EMAIL: lista separada por vírgulas das pastas a serem verificadas em busca de e-mails contendo os links para descadastramento.
  • KEYWORDS_FILE: caminho para o arquivo de texto contendo as palavras-chave a serem procuradas nos links dos e-mails. Cada palavra-chave deve estar em uma linha separada.

As variáveis de ambiente são carregadas a partir de um arquivo .env na raiz do projeto.

Funcionamento

Busca de e-mails

O script conecta-se à conta do Outlook e percorre as pastas indicadas em FOLDERS_EMAIL, buscando e-mails não lidos (se UNSEEN for "True") ou todos os e-mails (caso contrário).

Para cada e-mail encontrado, o script verifica se o conteúdo do e-mail é HTML. Se for, extrai os links contidos no HTML usando a biblioteca BeautifulSoup. Em seguida, verifica se algum desses links contém alguma das palavras-chave presentes no arquivo indicado em KEYWORDS_FILE.

Caso algum link contenha uma das palavras-chave, o script armazena as informações do e-mail (remetente e assunto) e o link em um dicionário e adiciona esse dicionário a uma lista.

Geração do arquivo HTML

Com a lista de informações dos links de descadastramento em mãos, o script gera um arquivo HTML a partir de um modelo localizado em templates/template.html.

O modelo HTML contém uma tabela com as informações do remetente, assunto e link de descadastramento. O script preenche as linhas dessa tabela com as informações armazenadas na lista de dicionários.

O arquivo HTML gerado é salvo em unsubscribe_links.html.

Uso

Antes de executar o script, é necessário definir as variáveis de ambiente no arquivo .env e criar um arquivo keywords.txt com as palavras-chave que devem ser procuradas nos links dos e-mails.

O arquivo unsubscribe_links.html será gerado na mesma pasta do script, contendo a tabela com os links de descadastramento encontrados nos e-mails.

To-do para execução do script:

  1. Renomear o arquivo .env.sample para .env;
mv .env.sample .env
  1. Preencher as informações do arquivo .env com as credenciais do Outlook e as variáveis de ambiente necessárias;

Exemplo de arquivo .env:

EMAIL_ADDRESS=johndoe@outlook.com
EMAIL_PASSWORD=mypassword
IMAP_SERVER=outlook.office365.com
IMAP_SSL=True
UNSEEN=True
FOLDERS_EMAIL=Inbox,Sent Items
KEYWORDS_FILE=keywords.txt
  1. Criar um arquivo keywords.txt na raiz do projeto com as palavras-chave a serem procuradas nos links dos e-mails;

Exemplo de arquivo keywords.txt:

unsubscribe
descadastre-se
cancelar inscrição
descadastrar
descadastrar-se
Update Profile
unsubscribe here
  1. Instalar as dependências do projeto usando o comando pip install -r requirements.txt no terminal;

  2. Salve o o conteudo abaixo em um arquivo chamado script.py

import imapclient
import email
import os
from dotenv import load_dotenv
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from email.header import decode_header

# carrega as variáveis de ambiente do arquivo .env
load_dotenv()

# Insira suas credenciais do Outlook aqui
email_address = os.getenv('EMAIL_ADDRESS')
email_password = os.getenv('EMAIL_PASSWORD')

# Leia as palavras-chave de um arquivo de texto
with open('keywords.txt', 'r', encoding='utf-8') as file:
    keywords = [line.strip().lower() for line in file]

unseen_only = os.getenv('UNSEEN')
if unseen_only is None or unseen_only.lower() == 'true':
    search_criteria = ['UNSEEN']
else:
    search_criteria = ['ALL']

# Conectar à caixa de entrada do Outlook
imap_server = os.getenv('IMAP_SERVER')
imap_ssl = os.getenv('IMAP_SSL')
client = imapclient.IMAPClient(imap_server, ssl=imap_ssl)
client.login(email_address, email_password)
folders = os.getenv('FOLDERS_EMAIL').split(',')
links_info = []

for folder in folders:
    # Conectar à pasta atual
    client.select_folder(folder, readonly=True)

    # Buscar e-mails não lidos
    messages = client.search(search_criteria)

    # Iterar pelos e-mails
    for msg_id in messages:
        msg_data = client.fetch(msg_id, ['RFC822'])
        msg = email.message_from_bytes(msg_data[msg_id][b'RFC822'])

        # Verificar se o e-mail é HTML
        if msg.is_multipart():
            for part in msg.walk():
                if part.get_content_type() == 'text/html':
                    html_content = part.get_payload(decode=True)
                    break
        else:
            if msg.get_content_type() == 'text/html':
                html_content = msg.get_payload(decode=True)
            else:
                continue

        # Extrair links usando BeautifulSoup
        soup = BeautifulSoup(html_content, 'html.parser')
        for link in soup.find_all('a', href=True):
            href = link['href']
            text = link.text.lower()

            # Verificar se alguma das palavras-chave está presente no texto do link
            if any(keyword in text for keyword in keywords):
                # Evitar links repetidos
                if href not in [info['link'] for info in links_info]:
                    # Decodificar o campo "From"
                    decoded_from = decode_header(msg['From'])
                    from_email = ''.join([str(part, encoding or 'utf-8') if isinstance(part, bytes) else part for part, encoding in decoded_from])

                    # Decodificar o campo "Subject"
                    decoded_subject = decode_header(msg['Subject'])
                    #subject = ''.join([str(part, encoding or 'utf-8') if isinstance(part, bytes) else part for part, encoding in decoded_subject])
                    subject = ''.join([str(part, encoding or 'utf-8') if isinstance(part, bytes) else part for part, encoding in decoded_subject if encoding != 'unknown-8bit'])

                    # Armazenar informações em um dicionário
                    link_info = {'from': from_email, 'subject': subject, 'link': href}
                    links_info.append(link_info)
                    # print(f'Link encontrado: {href}')

# Encerrar a conexão com o servidor de e-mail
client.logout()

# Gerar conteúdo HTML
template_path = os.path.join(os.path.dirname(__file__), 'templates', 'template.html')

with open(template_path, 'r') as f:
    html_template = f.read()

# Gerar linhas da tabela
table_rows = ''
for info in links_info:
    row = f'<tr><td>{info["from"]}</td><td>{info["subject"]}</td><td><a href="{info["link"]}">Clique aqui para descadastrar</a></td></tr>'
    table_rows += row

# Combinar modelo HTML e linhas da tabela
html_content = html_template.format(table_rows=table_rows)

# Salvar conteúdo HTML em um arquivo
with open('unsubscribe_links.html', 'w', encoding='utf-8') as file:
    file.write(html_content)

print('Arquivo HTML gerado: unsubscribe_links.html')
  1. Executar o script usando o comando python unsubscribe_links.py no terminal;

  2. Verificar se o arquivo unsubscribe_links.html foi gerado com sucesso na raiz do projeto.