😶🌫️添加邮件模板以美观
This commit is contained in:
		@@ -31,6 +31,7 @@ rss_subscribe:
 | 
				
			|||||||
  github_username: willow-god
 | 
					  github_username: willow-god
 | 
				
			||||||
  github_repo: Friend-Circle-Lite
 | 
					  github_repo: Friend-Circle-Lite
 | 
				
			||||||
  your_blog_url: https://blog.qyliu.top/
 | 
					  your_blog_url: https://blog.qyliu.top/
 | 
				
			||||||
 | 
					  email_template: "./rss_subscribe/email_template.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SMTP 配置
 | 
					# SMTP 配置
 | 
				
			||||||
# 解释:使用其中的相关配置实现上面两种功能,若无推送要求可以不配置,请将以上两个配置置为false
 | 
					# 解释:使用其中的相关配置实现上面两种功能,若无推送要求可以不配置,请将以上两个配置置为false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
import smtplib
 | 
					import smtplib
 | 
				
			||||||
from email.mime.multipart import MIMEMultipart
 | 
					from email.mime.multipart import MIMEMultipart
 | 
				
			||||||
from email.mime.text import MIMEText
 | 
					from email.mime.text import MIMEText
 | 
				
			||||||
 | 
					from jinja2 import Environment, FileSystemLoader
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def email_sender(
 | 
					def email_sender(
 | 
				
			||||||
    target_email, 
 | 
					    target_email, 
 | 
				
			||||||
@@ -10,6 +12,8 @@ def email_sender(
 | 
				
			|||||||
    password, 
 | 
					    password, 
 | 
				
			||||||
    subject, 
 | 
					    subject, 
 | 
				
			||||||
    body,
 | 
					    body,
 | 
				
			||||||
 | 
					    template_path=None,
 | 
				
			||||||
 | 
					    template_data=None,
 | 
				
			||||||
    use_tls=True,
 | 
					    use_tls=True,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -20,11 +24,12 @@ def email_sender(
 | 
				
			|||||||
    sender_email (str): 发信邮箱地址。
 | 
					    sender_email (str): 发信邮箱地址。
 | 
				
			||||||
    smtp_server (str): SMTP 服务地址。
 | 
					    smtp_server (str): SMTP 服务地址。
 | 
				
			||||||
    port (int): SMTP 服务端口。
 | 
					    port (int): SMTP 服务端口。
 | 
				
			||||||
    use_ssl (bool): 是否使用 SSL 加密。
 | 
					 | 
				
			||||||
    username (str): SMTP 服务用户名。
 | 
					 | 
				
			||||||
    password (str): SMTP 服务密码。
 | 
					    password (str): SMTP 服务密码。
 | 
				
			||||||
    subject (str): 邮件主题。
 | 
					    subject (str): 邮件主题。
 | 
				
			||||||
    body (str): 邮件内容。
 | 
					    body (str): 邮件内容。
 | 
				
			||||||
 | 
					    template_path (str): HTML 模板文件路径。默认为 None。
 | 
				
			||||||
 | 
					    template_data (dict): 渲染模板的数据。默认为 None。
 | 
				
			||||||
 | 
					    use_tls (bool): 是否使用 TLS 加密。默认为 True。
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    # 创建 MIME 对象
 | 
					    # 创建 MIME 对象
 | 
				
			||||||
    msg = MIMEMultipart()
 | 
					    msg = MIMEMultipart()
 | 
				
			||||||
@@ -32,8 +37,15 @@ def email_sender(
 | 
				
			|||||||
    msg['To'] = target_email
 | 
					    msg['To'] = target_email
 | 
				
			||||||
    msg['Subject'] = subject
 | 
					    msg['Subject'] = subject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 添加邮件内容
 | 
					    if template_path and template_data:
 | 
				
			||||||
    msg.attach(MIMEText(body, 'plain'))
 | 
					        # 使用 Jinja2 渲染 HTML 模板
 | 
				
			||||||
 | 
					        env = Environment(loader=FileSystemLoader(os.path.dirname(template_path)))
 | 
				
			||||||
 | 
					        template = env.get_template(os.path.basename(template_path))
 | 
				
			||||||
 | 
					        html_content = template.render(template_data)
 | 
				
			||||||
 | 
					        msg.attach(MIMEText(html_content, 'html'))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        # 添加纯文本邮件内容
 | 
				
			||||||
 | 
					        msg.attach(MIMEText(body, 'plain'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 连接到 SMTP 服务器并发送邮件
 | 
					    # 连接到 SMTP 服务器并发送邮件
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@@ -46,7 +58,7 @@ def email_sender(
 | 
				
			|||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        print(f'无法发送邮件到 {target_email}. 错误: {e}')
 | 
					        print(f'无法发送邮件到 {target_email}. 错误: {e}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_emails(emails, sender_email, smtp_server, port, password, subject, body, use_tls=True):
 | 
					def send_emails(emails, sender_email, smtp_server, port, password, subject, body, template_path=None, template_data=None, use_tls=True):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    循环发送邮件给指定的多个邮箱。
 | 
					    循环发送邮件给指定的多个邮箱。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,12 +70,11 @@ def send_emails(emails, sender_email, smtp_server, port, password, subject, body
 | 
				
			|||||||
    password (str): SMTP 服务密码。
 | 
					    password (str): SMTP 服务密码。
 | 
				
			||||||
    subject (str): 邮件主题。
 | 
					    subject (str): 邮件主题。
 | 
				
			||||||
    body (str): 邮件内容。
 | 
					    body (str): 邮件内容。
 | 
				
			||||||
    use_tls (bool): 是否使用 TLS 加密,默认为 True。
 | 
					    template_path (str): HTML 模板文件路径。默认为 None。
 | 
				
			||||||
 | 
					    template_data (dict): 渲染模板的数据。默认为 None。
 | 
				
			||||||
 | 
					    use_tls (bool): 是否使用 TLS 加密。默认为 True。
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    for email in emails:
 | 
					    for email in emails:
 | 
				
			||||||
        print(f'正在发送邮件到 {email}')
 | 
					        print(f'正在发送邮件到 {email}')
 | 
				
			||||||
        print(f'---------------------------\n邮件主题: {subject}\n邮件内容: {body}\n发件人: {sender_email}\n---------------------------')
 | 
					        print(f'---------------------------\n邮件主题: {subject}\n邮件内容: {body}\n发件人: {sender_email}\n---------------------------')
 | 
				
			||||||
        email_sender(email, sender_email, smtp_server, port, password, subject, body, use_tls)
 | 
					        email_sender(email, sender_email, smtp_server, port, password, subject, body, template_path, template_data, use_tls)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -3,3 +3,4 @@ python-dateutil==2.9.0.post0
 | 
				
			|||||||
requests
 | 
					requests
 | 
				
			||||||
feedparser==6.0.11
 | 
					feedparser==6.0.11
 | 
				
			||||||
PyYAML==6.0.1
 | 
					PyYAML==6.0.1
 | 
				
			||||||
 | 
					jinja2==3.1.2
 | 
				
			||||||
							
								
								
									
										135
									
								
								rss_subscribe/email_template.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								rss_subscribe/email_template.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
				
			||||||
 | 
					    <title>最新文章通知</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					        body {
 | 
				
			||||||
 | 
					            font-family: Arial, sans-serif;
 | 
				
			||||||
 | 
					            background-color: #f4f4f4;
 | 
				
			||||||
 | 
					            margin: 0;
 | 
				
			||||||
 | 
					            padding: 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .container {
 | 
				
			||||||
 | 
					            background-color: #ffffff;
 | 
				
			||||||
 | 
					            margin: 50px auto;
 | 
				
			||||||
 | 
					            padding: 40px;
 | 
				
			||||||
 | 
					            border-radius: 10px;
 | 
				
			||||||
 | 
					            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
 | 
				
			||||||
 | 
					            width: 80%;
 | 
				
			||||||
 | 
					            max-width: 600px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .header {
 | 
				
			||||||
 | 
					            margin-top: 30px;
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            padding-bottom: 20px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .header h1 {
 | 
				
			||||||
 | 
					            margin: 0;
 | 
				
			||||||
 | 
					            white-space: nowrap;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            text-overflow: ellipsis;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .content {
 | 
				
			||||||
 | 
					            font-size: 16px;
 | 
				
			||||||
 | 
					            line-height: 1.6;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .content p {
 | 
				
			||||||
 | 
					            margin: 10px 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        .content .title {
 | 
				
			||||||
 | 
					            display: inline-block;
 | 
				
			||||||
 | 
					            max-width: 100%;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            text-overflow: ellipsis;
 | 
				
			||||||
 | 
					            white-space: nowrap;
 | 
				
			||||||
 | 
					            vertical-align: middle;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .content p strong {
 | 
				
			||||||
 | 
					            display: inline-block;
 | 
				
			||||||
 | 
					            max-width: 100px;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            text-overflow: ellipsis;
 | 
				
			||||||
 | 
					            white-space: nowrap;
 | 
				
			||||||
 | 
					            vertical-align: middle;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .content .summary {
 | 
				
			||||||
 | 
					            display: -webkit-box;
 | 
				
			||||||
 | 
					            -webkit-box-orient: vertical;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            text-overflow: ellipsis;
 | 
				
			||||||
 | 
					            word-wrap: break-word;
 | 
				
			||||||
 | 
					            word-break: break-all;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .content .published {
 | 
				
			||||||
 | 
					            display: inline-block;
 | 
				
			||||||
 | 
					            max-width: 100%;
 | 
				
			||||||
 | 
					            overflow: hidden;
 | 
				
			||||||
 | 
					            text-overflow: ellipsis;
 | 
				
			||||||
 | 
					            white-space: nowrap;
 | 
				
			||||||
 | 
					            vertical-align: middle;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .button {
 | 
				
			||||||
 | 
					            display: block;
 | 
				
			||||||
 | 
					            width: 200px;
 | 
				
			||||||
 | 
					            max-width: 100%;
 | 
				
			||||||
 | 
					            margin: 20px auto;
 | 
				
			||||||
 | 
					            padding: 10px 20px;
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            background-color: #007bff;
 | 
				
			||||||
 | 
					            color: #ffffff;
 | 
				
			||||||
 | 
					            text-decoration: none;
 | 
				
			||||||
 | 
					            border-radius: 5px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .button:hover {
 | 
				
			||||||
 | 
					            background-color: #0056b3;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        @media (max-width: 300px) {
 | 
				
			||||||
 | 
					            .button {
 | 
				
			||||||
 | 
					                width: auto;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .footer {
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            margin-top: 20px;
 | 
				
			||||||
 | 
					            font-size: 18px;
 | 
				
			||||||
 | 
					            color: #777777;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .unsubscribe {
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            margin-top: 60px;
 | 
				
			||||||
 | 
					            font-size: 12px;
 | 
				
			||||||
 | 
					            color: #777777;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .unsubscribe a {
 | 
				
			||||||
 | 
					            color: #777777;
 | 
				
			||||||
 | 
					            text-decoration: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .unsubscribe a:hover {
 | 
				
			||||||
 | 
					            text-decoration: underline;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <div class="container">
 | 
				
			||||||
 | 
					        <div class="header">
 | 
				
			||||||
 | 
					            <h1>清羽飞扬の最新文章</h1>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="content">
 | 
				
			||||||
 | 
					            <p><strong>文章标题:</strong> <span class="title">{{ title }}</span></p>
 | 
				
			||||||
 | 
					            <p><strong>文章内容:</strong> <span class="summary">{{ summary }}</span></p>
 | 
				
			||||||
 | 
					            <p><strong>发布时间:</strong> <span class="published">{{ published }}</span></p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <a href="{{ link }}" class="button">阅读更多</a>
 | 
				
			||||||
 | 
					        <div class="footer">
 | 
				
			||||||
 | 
					            <p>感谢您的订阅!</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="unsubscribe">
 | 
				
			||||||
 | 
					            <p><a href="https://github.com/willow-god/Friend-Circle-Lite/issues">取消订阅</a></p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
@@ -1,13 +1,5 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "articles": [
 | 
					    "articles": [
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "title": "Spikformer脉冲神经网络学习",
 | 
					 | 
				
			||||||
            "author": "",
 | 
					 | 
				
			||||||
            "link": "https://blog.qyliu.top/posts/67189760/",
 | 
					 | 
				
			||||||
            "published": "2024-07-06 05:33",
 | 
					 | 
				
			||||||
            "summary": "近期我们进行了人工智能实训,我们小组选择的是脉冲神经网络,不同于原先的神经网络,这个网络采用的是脉冲信号,目前脉冲神经网络的效果并不是很好,但是因为是一个全新的神经网络架构,并且基于生物启发的计算方式,使得它们在处理稀疏和非结构化数据时具有独特的优势。",
 | 
					 | 
				
			||||||
            "content": "近期我们进行了人工智能实训,我们小组选择的是脉冲神经网络,不同于原先的神经网络,这个网络采用的是脉冲信号,目前脉冲神经网络的效果并不是很好,但是因为是一个全新的神经网络架构,并且基于生物启发的计算方式,使得它们在处理稀疏和非结构化数据时具有独特的优势。"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "title": "东软软件园实习日记",
 | 
					            "title": "东软软件园实习日记",
 | 
				
			||||||
            "author": "",
 | 
					            "author": "",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								run.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								run.py
									
									
									
									
									
								
							@@ -38,6 +38,7 @@ if config["rss_subscribe"]["enable"]:
 | 
				
			|||||||
    github_username = config["rss_subscribe"]["github_username"]
 | 
					    github_username = config["rss_subscribe"]["github_username"]
 | 
				
			||||||
    github_repo = config["rss_subscribe"]["github_repo"]
 | 
					    github_repo = config["rss_subscribe"]["github_repo"]
 | 
				
			||||||
    your_blog_url = config["rss_subscribe"]["your_blog_url"]
 | 
					    your_blog_url = config["rss_subscribe"]["your_blog_url"]
 | 
				
			||||||
 | 
					    email_template = config["rss_subscribe"]["email_template"]
 | 
				
			||||||
    # 获取最近更新的文章
 | 
					    # 获取最近更新的文章
 | 
				
			||||||
    latest_articles = get_latest_articles_from_link(
 | 
					    latest_articles = get_latest_articles_from_link(
 | 
				
			||||||
        url=your_blog_url,
 | 
					        url=your_blog_url,
 | 
				
			||||||
@@ -58,6 +59,13 @@ if config["rss_subscribe"]["enable"]:
 | 
				
			|||||||
            print("获取到的邮箱列表为:", email_list)
 | 
					            print("获取到的邮箱列表为:", email_list)
 | 
				
			||||||
        # 循环latest_articles,发送邮件
 | 
					        # 循环latest_articles,发送邮件
 | 
				
			||||||
        for article in latest_articles:
 | 
					        for article in latest_articles:
 | 
				
			||||||
 | 
					            template_data = {
 | 
				
			||||||
 | 
					                "title": article["title"],
 | 
				
			||||||
 | 
					                "summary": article["summary"],
 | 
				
			||||||
 | 
					                "published": article["published"],
 | 
				
			||||||
 | 
					                "link": article["link"]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            send_emails(
 | 
					            send_emails(
 | 
				
			||||||
                emails=email_list["emails"],
 | 
					                emails=email_list["emails"],
 | 
				
			||||||
                sender_email=email,
 | 
					                sender_email=email,
 | 
				
			||||||
@@ -66,5 +74,7 @@ if config["rss_subscribe"]["enable"]:
 | 
				
			|||||||
                password=password,
 | 
					                password=password,
 | 
				
			||||||
                subject="清羽飞扬の最新文章:" + article["title"],
 | 
					                subject="清羽飞扬の最新文章:" + article["title"],
 | 
				
			||||||
                body="文章链接:" + article["link"] + "\n" + "文章内容:" + article["summary"] + "\n" + "发布时间:" + article["published"],
 | 
					                body="文章链接:" + article["link"] + "\n" + "文章内容:" + article["summary"] + "\n" + "发布时间:" + article["published"],
 | 
				
			||||||
 | 
					                template_path=email_template,
 | 
				
			||||||
 | 
					                template_data=template_data,
 | 
				
			||||||
                use_tls=use_tls
 | 
					                use_tls=use_tls
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user