Home > Enterprise >  How do I fix this error when trying to schedule daily emails on python?
How do I fix this error when trying to schedule daily emails on python?

Time:09-30

I'm trying to send a data frame to myself daily via email. I've gotten this far and everything works but when I try to send it at a specific time I get this error

'the first argument must be callable' - referencing the fact that I'm calling a function within the parentheses.

Any ways to fix this? Also now that I have this set up, if I close my program, will it continue to run the script so that it executes daily?

Thanks,

def email_new(df):
    message = MIMEMultipart()
    message['Subject'] = "Subject"
    message['From'] = '[email protected]'
    message['To'] = '[email protected]'
    
    html = MIMEText(df.to_html(index=False), "html")
    message.attach(html)
    with smtplib.SMTP("smtp.office365.com", 587) as server:
        server.starttls()
        server.login('[email protected]','password')
        server.sendmail('[email protected]', 'email.edu', message.as_string())


        
schedule.every().day.at('17:40').do(email_new(df))



while True: 
    schedule.run_pending()
    time.sleep(1)

CodePudding user response:

do() takes the arguments to pass to the function in a second parameter:

schedule.every().day.at('17:40').do(email_new,df)

CodePudding user response:

I'm not familiar with this .do method, but in general, you can partially instantiate your email_new function using functools.partial. In this way, you can just pass your partially instantiated email_new function directly to the .do method.

Let's start with a toy example:

from functools import partial


def add_two_numbers(x, y):
    return x   y

add_5_10 = partial(add_two_numbers, 5, 10)
print(add_5_10())  # 15

Now with your example:

from functools import partial


def email_new(df):
    message = MIMEMultipart()
    message['Subject'] = "Subject"
    message['From'] = '[email protected]'
    message['To'] = '[email protected]'
    
    html = MIMEText(df.to_html(index=False), "html")
    message.attach(html)
    with smtplib.SMTP("smtp.office365.com", 587) as server:
        server.starttls()
        server.login('[email protected]','password')
        server.sendmail('[email protected]', 'email.edu', message.as_string())


email_new_df = partial(email_new, df)
schedule.every().day.at('17:40').do(email_new_df)

while True: 
    schedule.run_pending()
    time.sleep(1)

As for scheduling while you're away from your laptop, I'd recommend learning about Cron Jobs. However, your laptop must be awake and able to perform the process. In this case, perhaps a remote computer or a Raspberry Pi might be a good idea.

CodePudding user response:

See the schedule module examples for passing arguments to your function here: https://schedule.readthedocs.io/en/stable/examples.html#pass-arguments-to-a-job

You pass arguments for your function as additional parameters to the do method. For your schedule you would use

schedule.every().day.at('17:40').do(email_new, df)
  • Related