Редактирование сообщения в электронном письме на Python с помощью smtplib

#python #pandas #email #ssl #smtplib

#python #панды #Адрес электронной почты #ssl #smtplib

Вопрос:

Итак, я создал эту простую программу, которая каждый час проверяет мои исследовательские данные на nan. Это работает нормально, но я хочу улучшить электронное письмо, которое оно отправляет мне, когда находит nan. На данный момент я могу заставить его отправлять мне по электронной почте только то, что я помещаю в три речевых знака, например
message = """Missing data, yo."""

Я хочу, чтобы он отправил мне по электронной почте дату, время и имя файла, когда у него есть nan. Я пробовал следующее, но это не работает:

message = f"Hello, Cairan. {full_name} has missing data."

и я пробовал это, но это не сработало:

message = """Missing data """ full_name

Я не знаю, что я здесь делаю не так — пожалуйста, помогите. Я также был бы признателен за любые советы о том, как изменить заголовок темы для электронного письма.

Спасибо!

 # -*- coding: utf-8 -*-
"""
This Python script was written for use on an Amazon EC2 server, with the Eltek GPRS Server running.

This code has a 60 minute loop, which:

1. Copies the data from its original location to a temporary 'checking' directory.
2. Imports the listed CSV files
3. Converts all 'No Data' into nans
4. Looks at the last 12 observations and checks if there is any nans - if there are any it will email an email address about the nans.
5. Loops over all files
6. Loops every hour

"""
# Import packages

import os #os
import fnmatch #fn match
import pandas as pd #pandas
import numpy as np #numpy
import sched #scheduler
import time # time
import smtplib #for email
import ssl #for email
from datetime import datetime #datetime
from termcolor import colored #for colouring text

from shutil import copyfile

# Scheduler           
s = sched.scheduler(time.time, time.sleep)

# Email
user = '####@gmail.com' #email username (gmail tested and working)
sender = '####@gmail.com' #sendee email address
password = '####' #email password
port = 465 #port - 465 standard
recieve = '####'
context = ssl.create_default_context()

directory = "C:/EltekGateway/"
individual_files = "K01817-12158.csv", "K01830-12197.csv", "K01830-12200.csv"
files = "C:/EltekGateway/checking/K01817-12158.csv", "C:/EltekGateway/checking/K01830-12197.csv", "C:/EltekGateway/checking/K01830-12200.csv"

for full_name in individual_files:
    checking_dir = directory   "checking/"   full_name
    original_dir = directory   full_name
    copyfile(original_dir, checking_dir)
    print(original_dir, checking_dir)

def do_something(sc):
    now = datetime.now()
    print('<---------------------------------------------------------------------------------->')
    print('Checking:' , len(files), 'datafiles.', 'Time now =', now)
    for full_name in files:
        df_tmp= pd.read_csv(full_name, skiprows = 5) # read csv to df_tmp
        df_tmp.rename({'TX Channel': 'date'}, axis=1, inplace=True) # rename cols
        df_tmp['date'] = pd.to_datetime(df_tmp['date'], errors='raise', dayfirst=True) # create datetime col
        df_tmp = df_tmp.replace('No Data', np.nan) # Eltek 'No Data' to nan
        df_check = df_tmp[-12:]
        df_check = df_check.isnull().values.any()
        # df_check = df_check.isna() # Check last observation to see if there is a nan
        df_check_time = df_tmp.date.iloc[-1] # Store datetime for last obs
        now = datetime.now()
        date_string = df_check_time.strftime("%Y/%m/%d, %H:%M:%S")
        # print(df_check) #checking loop
        if df_check.any() == 0: # Check 
            print(date_string, full_name   colored(' - There is NO missing data','green'))
            # print()
        else:
            print(date_string, full_name   colored(' - There IS missing data', 'red'))
            message = """Missing data, yo."""
            # message = f"Hello, Cairan. {full_name} has missing data."
            with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
                server.login(sender, password)
                server.sendmail(sender, recieve, message)
        # print(df_tmp) #checking loop
        # print(full_name) #checking loop
        # print(df_check_time) #checking loop
    print('<---------------------------------------------------------------------------------->')
    s.enter(3600, 1, do_something, (sc,))

def main():
    s.enter(3600, 1, do_something, (s,))
    s.run()

if __name__ == "__main__":
    main()
 

Комментарии:

1. попробуйте это ` msg.as_string()`

2. уже пробовал .as_string() — не сработало

3. Какое сообщение об ошибке возвращается server.sendmail ?

4. «но это не работает» не помогает. Вы получили сообщение об ошибке? Если это так, опубликуйте полную обратную трассировку. Если вы не получили сообщение об ошибке, то как вы могли сказать, что оно «не работает»? Что произошло и чем это отличается от того, чего вы хотели.

5. Итак, когда я использовал .as_string(), код зависает, и цикл не завершается — ошибки нет

Ответ №1:

Ваше сообщение искажено.

Вы должны написать его с правильным заголовком и тому подобное, вот так:

 message = """
From: Robot <noreply@domain.com>
To: Persoon <persoon@gmail.com>
Subject: Something Fancy Happened!

Hi Persoon,

Your Thing caused Something Fancy!

Yours,

Robot.
"""
 

Если вы не хотите создавать сообщение вручную, взгляните на https://docs.python.org/3/library/email.html

Комментарии:

1. Я собирался написать это, то есть заголовки.. ты меня опередил

2. Я реализовал заголовок, как вы предлагаете, который отлично работает, когда он находится вне цикла, но я хочу, чтобы он был внутри цикла, чтобы я мог включить full_name его в электронное письмо. Но когда я помещаю весь код, который вы предлагаете, внутрь цикла — заменяя message = """Missing data, yo.""" в моем предыдущем коде, электронное письмо проходит, но в получаемом мной электронном письме все содержимое содержится в части From: в электронном письме, в теме или теле которого ничего нет

3. @CairanVanRooyen можете ли вы отредактировать свой вопрос и добавить к своему вопросу фрагмент блока, который начинается с if df_check.any() == 0: # Check того, что вы отредактировали?