【问题标题】:Unable To Stop Loop In Project Source Code无法在项目源代码中停止循环
【发布时间】:2020-02-22 17:35:25
【问题描述】:

我正在 Python 中构建一个自定义电子邮件发件人,使用示例 csv 数据作为输入。我已经完成了大部分脚本,但是我遇到的唯一问题是最后几行代码。如果您运行代码(确保包含您的电子邮件/密码),您会注意到自定义电子邮件会发送给正确的收件人,但是由于循环,他们会收到多个副本。

我在最后尝试了一个简单的中断语句,它只是发送第一封电子邮件然后停止。也无法在 google/youtube 上找到解决方案。

import datetime
import smtplib
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import pandas as pd

host = "smtp.gmail.com"
port = 587
usr = os.environ.get("EMAIL_USER")
pwd = os.environ.get("EMAIL_PASS")
from_email = usr


class MessageUser():
    user_details = []
    messages = []
    email_messages = []
    base_message = "Hi {name}!\n\nThank you for the purchase on {date}. We hope you are exited about using it. Just as a reminder the purchase total was ${total}. Have a great day!"
    def add_user(self, name, amount, email=None):
        name = name[0].upper() + name[1:].lower()
        amount = f"{amount}"
        detail = {
            "name": name,
            "amount": amount,
        }
        today = datetime.date.today()
        date_text = '{today.month}/{today.day}/{today.year}'.format(today=today)
        detail['date'] = date_text
        if email is not None:   # if email != None
            detail["email"] = email
        self.user_details.append(detail)
    def get_details(self):
        return self.user_details
    def make_messages(self):
        if len(self.user_details) > 0:
            for detail in self.get_details():
                name = detail["name"]
                amount = detail["amount"]
                date = detail["date"]
                message = self.base_message
                new_msg = message.format(
                    name=name,
                    date=date,
                    total=amount
                )
                user_email = detail.get("email")
                if user_email:
                    user_data = {
                        "email": user_email,
                        "message": new_msg
                    }
                    self.email_messages.append(user_data)
                else:
                    self.messages.append(new_msg)
            return self.messages
        return []
    def send_email(self):
        self.make_messages()
        if len(self.email_messages) > 0:
            for detail in self.email_messages:
                user_email = detail['email']
                user_message = detail['message']
                try:
                    email_conn = smtplib.SMTP(host, port)
                    email_conn.ehlo()
                    email_conn.starttls()
                    email_conn.login(usr, pwd)
                    the_msg = MIMEMultipart("alternative")
                    the_msg["Subject"] = "Billing Update"
                    the_msg["From"] = from_email
                    the_msg["To"] = user_email
                    part_1 = MIMEText(user_message, "plain")
                    the_msg.attach(part_1)
                    email_conn.sendmail(from_email, [user_email], the_msg.as_string())
                except smtplib.SMTPException:
                    print("Error sending message.")
            return True
        return False

df = pd.read_csv('test_data.csv')

Name = df.Name
Amount = df.Price
Email = df.Email

for name, amount, email in zip(Name, Amount, Email):
    obj = MessageUser()
    obj.add_user(f'{name}', f'{amount}', email=f'{email}')
    obj.get_details()
    obj.send_email()

# Works but need loop break suggestion.
# Previous attempt with error. email.errors.HeaderParseError: header value appears to contain an embedded header.

name = df.Name[1:]
amount = df.Price[1:]
email = df.Email[1:]

obj = MessageUser()
obj.add_user(f'{name}', f'{amount}', email=f'{email}')
obj.get_details()
obj.send_email()

预期:向所有收件人发送一次自定义电子邮件。 实际:由于结束循环,多次收到自定义电子邮件。

【问题讨论】:

  • 我不认为这是循环中的问题。您确定.csv 文件中的所有电子邮件都是唯一的吗?你最好重新组织你的班级并检查对偶性。
  • 另外,仅供参考,因为我假设您是初学者。您可以将参数直接传递到函数中,而无需 f-strings (obj.add_user(name=name, amount=amount, email=email))。另外,请注意 obj.get_details() 在您的循环中实际上没有做任何事情。

标签: python string pandas loops smtp


【解决方案1】:

问题很可能是您的.csv 文件有重复的用户/电子邮件。您或许应该考虑更好地构建您的代码,以便能够更轻松地对其进行调试。

本质上,您希望确保将功能解耦,以便您可以单独测试每个功能,这样就不会发生此类情况。举个例子:

import pandas as pd

class User:
    def __init__(self, email, name, price):
        self.email = email
        self.name = name
        self.price = price

    def send_email_to_user(self):
        """ Sends email to the user. """
        SendEmail.send_email(self)

    def __eq__(self, other):
        """ Checks the equality of User by the standard == notation. """
        if (
            self.email == other.email
            and self.name == self.name
            and self.price == self.price
        ):
            return True
        else:
            return False


class SendEmail:
    @staticmethod
    def create_message(user):
        """ Creates the message template to be sent. """

        return f"<b>{user.name}: {user.email} for {user.price}</b>"

    @staticmethod
    def send_email(user):
        """ Sends email to passed user. """

        name = user.name
        email = user.email
        price = user.price

        message = SendEmail.create_message(user)

        print(f"Sending the message {message} to the user.")


data = {
    "name": ["name1", "name2", "name1", "name3"],
    "email": ["email1", "email2", "email1", "email3"],
    "price": ["$1", "$2", "$1", "$3"],
}
df = pd.DataFrame(data)

users = []
for name, email, price in zip(df.name, df.email, df.price):
    user = User(name, email, price)

    # We are using the __eq__ method here when we do "user not in users".
    if user not in users:
        users.append(user)
    else:
        print(
            f"It seems the user with the name {name} is already in the list of users."
        )

for user in users:
    user.send_email_to_user()

以上输出:

It seems the user with the name name1 is already in the list of users.
Sending the message <b>email1: name1 for $1</b> to the user.
Sending the message <b>email2: name2 for $2</b> to the user.
Sending the message <b>email3: name3 for $3</b> to the user.

请注意上面的代码如何解耦我们的功能。这样,我们可以更轻松地测试是否可以发送和模板化电子邮件(通过SendEmail 对象),当然,最终通过Users 类将电子邮件发送给用户。

【讨论】:

  • 感谢@Felipe Faria 的评论。但是,我希望发送到可能包含 100 或 1000 封电子邮件的列表,因此每次输入数据效率低下。这就是为什么我对 f 字符串感兴趣,但是当我运行它时它似乎无法正常工作。正如您之前提到的,我没有任何重复项,因为我的示例 csv 中只有 3 行,而且它们都是不同的。由于我还没有找到循环解决方案,我将不得不为每封电子邮件使用 obj.add_user。我仍然不确定如何将诸如 0 之类的值更改为 1 作为循环,但也许是正则表达式。再次感谢。
  • 这是我需要的解决方案。如果您知道如何按比例完成,请告诉我。
  • obj.add_user(df.Name[0], df.Price[0], email=df.Email[0]) obj.add_user(df.Name[1], df.Price[ 1], email=df.Email[1]) obj.add_user(df.Name[2], df.Price[2], email=df.Email[2]) obj.add_user(df.Name[3], df.Price[3], email=df.Email[3]) obj.add_user(df.Name[4], df.Price[4], email=df.Email[4]) obj.add_user(df.Name [5], df.Price[5], email=df.Email[5])
  • 在上面的代码中,我仍在使用 pd.DataFrame(data) 并循环遍历它,因此不需要添加每个单独的 df.Price[1]df.Price[2] ,...等等开。
  • 恐怕我很困惑。您的.csv 文件中只有 3 行?您的预期目标是什么 - 将单独的电子邮件发送到每封电子邮件,还是将多封电子邮件发送到一封电子邮件?
猜你喜欢
  • 2014-11-09
  • 2018-05-12
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
相关资源
最近更新 更多