[문과생도 AI] 받은 이메일 키워드 필터링해 요약된 이메일 발송하기

#11기문과생도AI

안녕하세요! 2주차 과제로 한 첫 시도는 선별된 메일별로 간단한 요약도 해보는 것이었는데요. GPT와 함께 구글 클라우드 내에서 Cloud Natural Language API를 연결해서 코드를 짜봤지만, 계속된 실패로 이메일 필터링까지만 시도하기로 했습니다.

문제

뉴스레터가 너무 많이 오는데 하나씩 읽고 정보를 걸러내기에 시간이 너무 오래걸림. 내가 원하는 키워드가 담긴 메일을 골라 daily brief가 이메일로 왔으면 좋겠다.

정기님이 추천해주신 GPTS 사용

과정

1. 필요한 라이브러리 설치: pip3 install apscheduler

2. 폴더 구조 만들기

email_monitoring_system/
│
├── config.py
├── email_monitor.py
├── scheduler.py

3. 각 파일별로 코드 입력하기

# config.py

EMAIL_ADDRESS = '[email protected]'
EMAIL_PASSWORD = 'xxxx xxxx xxxx xxxx'  # Use the app-specific password with spaces
IMAP_SERVER = 'imap.gmail.com'
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
KEYWORDS = ['solopreneur', 'marketing', 'growth', 'bootstrap', 'AI', 'no code', 'business model']
RECIPIENT_EMAIL = '[email protected]'
# scheduler.py
# This script will set up the task to run the email monitoring process at 10 AM daily.

from apscheduler.schedulers.blocking import BlockingScheduler
import email_monitor

scheduler = BlockingScheduler()

@scheduler.scheduled_job('cron', hour=10)
def scheduled_job():
    email_monitor.main()

scheduler.start()

Sheduler.py의 경우 스케줄링을 했지만, 그 시간에 이메일이 오지 않아서 제가 코드를 실행할 때 설정한 시간만큼의 이메일을 정리해 보내주는 형식으로 수정했습니다.

# run_email_monitor.py

import email_monitor

if __name__ == "__main__":
    email_monitor.main()

4. 이메일을 받아보니 Subject라인이 제대로 다 보이지 않았고, 인박스 전체에서 내용을 뽑은 듯한 느낌이 들었습니다

5. GPT가 subject decoding logic 강화하는 형식으로 코드를 수정

드디어 제대로 작동하기 시작했습니다. 그러나 AI관련 키워드의 이메일만 리스트업된 것 같아서 다른 키워드드들이 들어갈 수 있도록 코드를 수정하고 security alert와 제 이메일계정으로 보낸 이메일을 제외하도록 부탁했습니다.

6. 조금 더 필터링이 강화된 코드 작성

# email_monitor.py

import imaplib
import email
from email.header import decode_header, make_header
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timedelta
import config

def connect_to_email():
    try:
        mail = imaplib.IMAP4_SSL(config.IMAP_SERVER)
        mail.login(config.EMAIL_ADDRESS, config.EMAIL_PASSWORD)
        print("Connected to email.")
        return mail
    except Exception as e:
        print(f"Error connecting to email: {e}")
        return None

def keyword_in_body(body, keywords):
    return any(keyword.lower() in body.lower() for keyword in keywords)

def search_emails(mail, since_date):
    try:
        mail.select("inbox")
        status, messages = mail.search(None, f'(SINCE "{since_date}")')
        email_ids = messages[0].split()
        matched_emails = []

        for email_id in email_ids:
            status, msg_data = mail.fetch(email_id, '(RFC822)')
            msg = email.message_from_bytes(msg_data[0][1])
            
            from_address = email.utils.parseaddr(msg.get("From"))[1]
            subject = str(make_header(decode_header(msg["Subject"])))
            
            if from_address == config.EMAIL_ADDRESS or "security alert" in subject.lower() or "daily keyword email summary" in subject.lower():
                continue
            
            if msg.is_multipart():
                for part in msg.walk():
                    if part.get_content_type() == "text/plain":
                        body = part.get_payload(decode=True).decode()
                        if keyword_in_body(body, config.KEYWORDS):
                            email_info = {
                                'subject': subject,
                                'link': f"<https://mail.google.com/mail/u/0/#inbox/{email_id.decode()}>"
                            }
                            matched_emails.append(email_info)
                            break
                    elif part.get_content_type() == "text/html":
                        body = part.get_payload(decode=True).decode()
                        if keyword_in_body(body, config.KEYWORDS):
                            email_info = {
                                'subject': subject,
                                'link': f"<https://mail.google.com/mail/u/0/#inbox/{email_id.decode()}>"
                            }
                            matched_emails.append(email_info)
                            break
            else:
                body = msg.get_payload(decode=True).decode()
                if keyword_in_body(body, config.KEYWORDS):
                    email_info = {
                        'subject': subject,
                        'link': f"<https://mail.google.com/mail/u/0/#inbox/{email_id.decode()}>"
                    }
                    matched_emails.append(email_info)

        print(f"Matched emails: {matched_emails}")
        return matched_emails
    except Exception as e:
        print(f"Error searching emails: {e}")
        return []

def send_summary_email(matched_emails):
    if not matched_emails:
        print("No matched emails to send.")
        return

    message = MIMEMultipart()
    message["From"] = config.EMAIL_ADDRESS
    message["To"] = config.RECIPIENT_EMAIL
    message["Subject"] = "Daily Keyword Email Summary"

    email_content = "Here are the emails matching your keywords:\\n\\n"
    for email_info in matched_emails:
        email_content += f"Subject: {email_info['subject']}\\nLink: {email_info['link']}\\n\\n"

    message.attach(MIMEText(email_content, "plain"))

    try:
        with smtplib.SMTP(config.SMTP_SERVER, config.SMTP_PORT) as server:
            server.starttls()
            server.login(config.EMAIL_ADDRESS, config.EMAIL_PASSWORD)
            server.sendmail(config.EMAIL_ADDRESS, config.RECIPIENT_EMAIL, message.as_string())
        print("Summary email sent successfully.")
    except Exception as e:
        print(f"Error sending summary email: {e}")

def main(period_hours=24):
    mail = connect_to_email()
    if mail:
        since_date = (datetime.now() - timedelta(hours=period_hours)).strftime("%d-%b-%Y")
        matched_emails = search_emails(mail, since_date)
        send_summary_email(matched_emails)
        mail.logout()

if __name__ == "__main__":
    period_hours = int(input("Enter the number of hours to search back from now (e.g., 24 for last 24 hours): "))
    main(period_hours)


해결하지 못한 것

  • 필터링을 강화했지만 여전히 주문 확인 메일이나 다른 메일이 섞여서 들어오고 있습니다. 키워드를 뽑는 방식을 변경해봐야 할 것 같아요

  • 메일 별로 한줄 요약이 있었으면 좋겠는데, 아무래도 open ai api같은 것을 연결해야 하지 않을까 싶습니다

  • 이메일 계정이 여러개다 보니 여러 계정의 이메일을 한 번에 필터링하는 코드를 짜봐야할 것 같아요

  • 자동으로 아침에 보내지는 시스템 구축

  • Leo님 사례를 보니 텔레그램으로도 전송이 가능해 보여서 이메일 인박스에 또 다른 메일이 쌓이는 것보다 텔레그램으로 보내기를 시도해 봐야겠어요!

4
2개의 답글

뉴스레터 무료 구독