Python IMAP 收件

 最近遇到一个需求,就是一个朋友买了一个教育邮箱的账号,这个账号可以无限别名,这个朋友想卖教育账号赚钱,用laravel写了个PHP的接码网站,但是却迟迟困在电子邮件的收件了。因为很多服务都对教育账号有着免费或者优惠,所以干这行还是挺挣钱的。他知道我比较擅长Python,所以就咨询我有没有办法用Python写一个收电子邮件的接口。

朋友的请求我当然不会拒绝,况且这是一个很简单的项目!

我使用的是Miniconda,这个虚拟环境可以装很多不同版本的python。但是我喜欢在一般情况下使用Pipenv环境,所以我使用pipenv环境初始化这个项目。

# Terminal
$ mkdir email-receiver
$ cd email-receiver
$ git init
$ pipenv install flask
$ touch main.py

然后使用喜欢的编辑器写代码:

# main.py
import imaplib
import email
import flask
import random
import string

# 创建Flask对象
app = flask.Flask(__name__)
# 设置session加密,每次启动随机生成32位字母
app.secret_key = random.choices(string.ascii_letters,k=32)

# IMAP服务器信息
IMAP_SERVER = "imap.exmail.qq.com"
IMAP_PORT = 993

# IMAP类
class Mail:
    # 类初始化函数
    def __init__(self,username,password,inbox='INBOX'):
        self.username = username
        self.password = password
        self.mailbox = inbox
        self.connect()
        self.login()
        self.setbox()
        self.mails = []
        self.lastmail = 0
        self.pull()
    # 连接IMAP服务器
    def connect(self):
        self.conn = imaplib.IMAP4_SSL(IMAP_SERVER,IMAP_PORT)
    # 登录
    def login(self):
        self.conn.login(self.username,self.password)
        self.status = 1
    # 设置收件箱
    def setbox(self):
        self.conn.select(self.mailbox)
    # 拉取邮件
    def pull(self):
        result,data = self.conn.search(None,"ALL")
        if result!='OK':
            print("或许什么地方出错了")
        for i in data[0].split():
            if int(i)<=self.lastmail:
                continue
            self.lastmail = int(i)
            result,data = self.conn.fetch(i,"(RFC822)")
            if result!='OK':
                ("或许什么地方出错了")
            data = email.message_from_bytes(data[0][1])
            self.mails.append(
                {
                    "id": int(i),
                    "sender": data["From"],
                    "receiver": data["To"],
                    "subject": data["Subject"],
                    "time": data["Date"],
                    "content": data.get_payload(decode=True)
                }
            )
    # 断开与SMTP服务器的连接
    def disconnect(self):
        self.conn.close()
        self.conn.logout()
        self.status = 0

IMAP_CONNECTIONS = {}

# 路由/login路径,接收POST请求
@app.route("/login",methods=['POST'])
def login():
    # 临时变量,存储用户请求带有的信息,如果不存在返回None
    username = flask.request.form.get("username")
    password = flask.request.form.get("password")
    # 如果username或password中有任意为空(None),跳出并返回错误。
    if not username or not password:
        flask.session["errMsg"] = "未设置凭据"
        return flask.redirect("/login")
    # 否则登入服务器
    flask.session["imapkey"] = ''.join(random.choices(string.ascii_letters,k=16))
    IMAP_CONNECTIONS[flask.session["imapkey"]] = Mail(username,password)
    return flask.redirect("/mailbox")

# 路由/login,接受GET请求,返回HTML页面。
@app.route("/login",methods=['GET'])
def loginUI():
    return flask.render_template("loginPage.html",err=flask.session.get("errorMsg"))

# 路由/mailbox,接收GET请求,返回HTML页面。
@app.route("/mailbox",methods=['GET'])
def mailbox():
    srv  = flask.session.get("imapkey")
    if not srv: return flask.redirect("/login")
    imap = IMAP_CONNECTIONS.get(srv)
    if not imap: return flask.redirect("/login")
    return flask.render_template("mailList.html",mails=imap.mails)

# 路由/mail/{id},接收GET请求,返回HTML页面
@app.route("/mail/<id>",methods=['GET'])
def mail(id):
    srv  = flask.session.get("imapkey")
    if not srv: return flask.redirect("/login")
    imap = IMAP_CONNECTIONS.get(srv)
    if not imap: return flask.redirect("/login")
    mail = {"subject":"","content":""}
    for i in imap:
        if i["id"]==int(id):
            mail=i
            break
    return "<h1>%s</h1><div>%s</div>"%(mail["subject"],mail["content"])

# 刷新邮件列表
@app.route("/pullemails",methods=['GET'])
def pullEmails():
    srv  = flask.session.get("imapkey")
    if not srv: return flask.redirect("/login")
    imap = IMAP_CONNECTIONS.get(srv)
    if not imap: return flask.redirect("/login")
    imap.pull()
    return flask.redirect("/mailbox")

# 登出
@app.route("/logout",methods=['GET'])
def logout():
    srv = flask.session.get("imapkey")
    if srv:
        imap = IMAP_CONNECTIONS.get(srv)
        if imap:
            imap.disconnect()
            IMAP_CONNECTIONS.remove(imap)
    return flask.redirect("/login")

if __name__ == "__main__":
    app.debug = True
    app.run("127.0.0.1",7788)

HTML代码:

templates/loginPage.html

<!DOCTYPE html>
<html>
<head>
  <title>Email Login</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      background-color: #f4f4f4;
      text-align: center;
      padding-top: 100px;
    }

    .container {
      width: 300px;
      margin: 0 auto;
      background-color: #fff;
      padding: 20px;
      border-radius: 5px;
      box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2);
    }

    .container h2 {
      margin-bottom: 20px;
    }

    .container input[type="text"],
    .container input[type="password"] {
      width: 100%;
      padding: 10px;
      margin-bottom: 15px;
      border: 1px solid #ccc;
      border-radius: 3px;
      box-sizing: border-box;
    }

    .container input[type="submit"] {
      width: 100%;
      background-color: #4CAF50;
      color: #fff;
      padding: 10px;
      border: none;
      border-radius: 3px;
      cursor: pointer;
    }

    .container input[type="submit"]:hover {
      background-color: #45a049;
    }

    .err {
        color: red;
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>Email Login</h2>
    <form method="POST">
      <input type="text" name="username" placeholder="Email" required><br>
      <input type="password" name="password" placeholder="Password" required><br>
      <input type="submit" value="Login">
    </form>
  </div>
  <p class="err">{{err}}</p>
</body>
</html>


templates/mailList.html

<!DOCTYPE html>
<html>
<head>
  <title>Email Viewer</title>
</head>
<body>
  <p><a href="/pullemails">刷新邮件列表</a></p>
  <div class="email-list">
    <ul>
{% for i in range(len(mails)-1,-1,-1) %}
      <li onclick="loadEmail('/mail/{{mails[i]["id"]}}')">{{i["subject"]}}</li>
{% endfor %}
    </ul>
  </div>
    <div class="email-content">
      <iframe id="emailFrame" src="" frameborder="0"></iframe>
    </div>
  </div>

  <script>
    function loadEmail(url) {
      var iframe = document.getElementById('emailFrame');
      iframe.src = url;
    }
  </script>
</body>
</html>

(注:2023/8/13修改:删除了一些GPT生成的问题内容,目前页面较简陋,敬请理解!)

然后就可以流畅使用uwsgi或者直接执行程序来获得一个收件箱了!

886~

评论

此博客中的热门博文

IMAPBox:IMAP在线收件箱