Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Send emails daily
on:
workflow_dispatch:
schedule:
- cron: '0 22 * * *'
- cron: '0 4 * * *'

jobs:
calculate-and-send:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Below are all the secrets you need to set. They are invisible to anyone includin
| SMTP_PORT | ✅ | int | The port of SMTP server. | 465 |
| SENDER | ✅ | str | The email account of the SMTP server that sends you email. | abc@qq.com |
| SENDER_PASSWORD | ✅ | str | The password of the sender account. Note that it's not necessarily the password for logging in the e-mail client, but the authentication code for SMTP service. Ask your email provider for this. | abcdefghijklmn |
| RECEIVER | ✅ | str | The e-mail address that receives the paper list. | abc@outlook.com |
| RECEIVER | ✅ | str | The email address(es) that receive the paper list. Multiple addresses are supported and can be separated by **semicolons (`;`)**, **commas (`,`)**, or **spaces**. All listed addresses will receive the same daily email. Example: `abc@outlook.com;cde@qq.com 123@163.com,456@126.com` |abc@outlook.com;cde@qq.com 123@163.com,456@126.com |
| MAX_PAPER_NUM | | int | The maximum number of the papers presented in the email. This value directly affects the execution time of this workflow, because it takes about 70s to generate TL;DR for one paper. `-1` means to present all the papers retrieved. | 50 |
| SEND_EMPTY | | bool | Whether to send an empty email even if no new papers today. | False |
| USE_LLM_API | | bool | Whether to use the LLM API in the cloud or to use local LLM. If set to `1`, the API is used. Else if set to `0`, the workflow will download and deploy an open-source LLM. Default to `0`. | 0 |
Expand Down
48 changes: 37 additions & 11 deletions construct_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import datetime
import time
from loguru import logger

from typing import List
framework = """
<!DOCTYPE HTML>
<html>
Expand Down Expand Up @@ -149,21 +149,47 @@ def send_email(sender:str, receiver:str, password:str,smtp_server:str,smtp_port:
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
def _split_receivers(receiver_str: str) -> List[str]:
"""
"a@example.com, b@example.com; c@example.com"
"""
if not receiver_str:
return []
# support , ; <space>
return [r.strip() for r in receiver_str.replace(';', ',').split(',') if r.strip()]

receivers = _split_receivers(receiver)
if not receivers:
logger.warning("No valid receiver email addresses provided.")
return

msg = MIMEText(html, 'html', 'utf-8')
msg['From'] = _format_addr('Github Action <%s>' % sender)
msg['To'] = _format_addr('You <%s>' % receiver)
msg['From'] = _format_addr(f'Github Action <{sender}>')
today = datetime.datetime.now().strftime('%Y/%m/%d')
msg['Subject'] = Header(f'Daily arXiv {today}', 'utf-8').encode()

msg['To'] = ', '.join(_format_addr(f'You <{r}>') for r in receivers)

# ---------- SMTP ----------
try:
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
if smtp_port == 465: # QQ、Outlook
server = smtplib.SMTP_SSL(smtp_server, smtp_port, timeout=15)
logger.debug("Using SMTP_SSL (port 465).")
else: # 587、25
server = smtplib.SMTP(smtp_server, smtp_port, timeout=15)
server.starttls()
logger.debug("Using SMTP + STARTTLS.")
except Exception as e:
logger.warning(f"Failed to use TLS. {e}")
logger.warning(f"Try to use SSL.")
server = smtplib.SMTP_SSL(smtp_server, smtp_port)
logger.error(f"Failed to establish SMTP connection: {e}")
raise

server.login(sender, password)
server.sendmail(sender, [receiver], msg.as_string())
server.quit()
# ---------- login & send ----------
try:
server.login(sender, password)
server.sendmail(sender, receivers, msg.as_string())
logger.info(f"Email sent successfully to: {', '.join(receivers)}")
except Exception as e:
logger.error(f"SMTP login/send failed: {e}")
raise
finally:
server.quit()
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def get_env(key:str,default=None):
"--language",
type=str,
help="Language of TLDR",
default="English",
default="chinese",
)
parser.add_argument('--debug', action='store_true', help='Debug mode')
args = parser.parse_args()
Expand Down