13

I have a threaded python script that pings 20 nodes on a local area network, and prints out the status of each: Node is Alive, Node is Down, etc.. I would like to have this output sent to my email account, Because I intend to make this script to run once a week, on it's own, And if i'm physically away from the lan I won't have to worry, I can just check my email.

Language:PYTHON. OS:Linux Mint 10 Julia. Thanks

Samuel
  • 139
  • 1
  • 1
  • 4

6 Answers6

17

If it runs once a week, you will probably run it from crontab?

30 2 * * 5  python yourScript.py | mail -s outputFromScript your@email.address
eumiro
  • 207,213
  • 34
  • 299
  • 261
  • 3
    You probably want to pipe it (using "|") into mail, rather than redirecting into a file called something with spaces (depending on exactly how cron parses the command line), other than that it's a sane and sensible idea. – Vatine Mar 09 '11 at 15:12
  • 3
    @Vatine - you're absolutely right with the pipe, thank you, fixed! – eumiro Mar 09 '11 at 15:13
  • Cool, my +1 has already been given, but I give you one for your comment for doing the edit so quickly. – Vatine Mar 09 '11 at 15:16
  • @eumiro Let's say I have a simple MRSS feedparser script that runs every hour, what would I need to enter there for "outputFromScript" in Crontab? – AdjunctProfessorFalcon Jul 24 '15 at 19:36
12

Use smtplib. The example they provide is pretty good.

import smtplib

def prompt(prompt):
    return raw_input(prompt).strip()

fromaddr = prompt("From: ")
toaddrs  = prompt("To: ").split()
print "Enter message, end with ^D (Unix) or ^Z (Windows):"

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, ", ".join(toaddrs)))
while True:
    try:
        line = raw_input()
    except EOFError:
        break
    if not line:
        break
    msg += line

print "Message length is " + repr(len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
Sairam
  • 375
  • 1
  • 5
  • 28
chmullig
  • 13,006
  • 5
  • 35
  • 52
7

Instead of having your main print the output, you could use a logger to print to stout and to the logger

You can set up a logger as follows according to the Logging Cookbook:

import logging
log_file = r'C:\Users\user\Downloads\LogFileName.log'

logger = logging.getLogger('simple_example')
logger.setLevel(logging.INFO)

# create file handler which logs even debug messages
fh = logging.FileHandler('log_file')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)

Now in replace print in your script with logger.info

Example before:

print("Printing status")

Example after:

logger.info("Printing status")

Then you can email the log to yourself as follows:

import smtplib
from email.message import EmailMessage
import os
msg_body = "Body Text"

msg = EmailMessage()

msg['Subject'] = "Subject"
msg['From'] = "send_from@email.com"
msg['To'] = "send_to@email.com"

msg.set_content(msg_body)

if os.path.isfile(log_file):
        msg.add_attachment(open(log_file, "r").read(), filename=os.path.basename(log_file))


# Send the message via our own SMTP server.
s = smtplib.SMTP("smtpa.server")
s.send_message(msg)
s.quit()
C. Fennell
  • 992
  • 12
  • 20
6

Take a look at the logging and logging.config, I've used this before to receive error messages from a script running in the background

http://docs.python.org/library/logging.html

For example

import logging
import logging.config

logDir = "./logs/"

logging.config.fileConfig(logDir+'logging.conf')
logger = logging.getLogger('email')

logger.debug('THIS IS A DEBUG MESSAGE')
logger.error('THIS IS AN ERROR')

And then the logging.conf

[loggers]
keys=root,email

[logger_root]
level=DEBUG
handlers=rotatingFileHandler

[logger_email]
level=ERROR
handlers=email
qualname=email

[formatters]
keys=emailFormatter,rotatingFormatter

[formatter_emailFormatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s

[formatter_rotatingFormatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
datefmt=%m-%d %H:%M

[handlers]
keys=email,rotatingFileHandler

[handler_email]
class=handlers.SMTPHandler
level=ERROR
formatter=emailFormatter
args=('mail.xxx','x@x.com',['y@y.com',],'ERROR!',('x@x.com','xxx'))

[handler_rotatingFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=rotatingFormatter
args=('./logs/log.out', 'maxBytes=1000000', 'backupCount=5')

From the above I would receive "THIS IS AN ERROR" in my email.

PDStat
  • 5,513
  • 10
  • 51
  • 86
2

A great resource on the topic of sending email with Python is Al Sweigart's 'Automate the Boring Stuff with Python'. Chapter 18 is the part you want. In short, if you have an email address with one of the big email providers (think Google, Outlook, Yahoo, etc.) you can use their Simple Mail Transfer Protocol (SMTP) server(s) to handle your messages from Python. As Al says:

enter image description here

If you don't have an email address with one of the big providers or you're not in a position where you can use an email address from an outside provider, then it's a bit harder. Perhaps someone at your company can tell you 1) if your company has an SMTP server and 2) what its domain name and port number are.

Once you have all that, sending out an email message from your program is a piece of cake:

import smtplib

def main():

    # get message from node
    message1 = 'Node 1 is up :)'
    # print message from node
    print(message1)
    # get message from another node
    message2 = 'Node 2 is down :('
    # print that too
    print(message2)

    # now, all done talking to nodes.
    # time to compile node response results and send an email.

    # first, let's get every thing setup for the email
    from_me = 'awesome.name@my_email_provider.com'
    to_me = 'awesome.name@my_email_provider.com'
    email_message = message1 + '\n' + message2

    # second, let's make sure we have a connection to a Simple Mail Transfer Protocol (SMTP) server 
    # this server will receive and then send out our email message
    domain_name = 'smtp.my_email_provider.com'
    port_number = 587  # or maybe, 465
    server = smtplib.SMTP(domain_name, port_number)

    # alright! if that last line didn't raise an exceptions, then you're good to go. Send that bad boy off.
    server.sendmail(from_me, to_me, email_message)

if __name__ == '__main__':
    main()

Loggers are great too, so don't discount what everyone's said about them. Print to the terminal. Log to a file. AND email out! Loggers can do everything.

Steve
  • 473
  • 2
  • 12
  • How would you record all of the messages? If they have 20 nodes would you suggest they have `message1` through `message20` and write them all to the email like this: `email_message = message1 + '\n' + message2+ '\n' + message3 + '\n' + message4 + '\n' + message5` etc? – C. Fennell Apr 13 '20 at 19:45
  • No. I wouldn't recommend that. The code was intended as a toy example with an emphasis on how to send an email from Python. At the very least, a list and `join` call for storing and compiling the messages would seem reasonable. But really, your solution using a logger is certainly more robust and versatile. – Steve Apr 14 '20 at 02:12
  • @Steve, how can i send attachments from same program, like in my case when i ran program it creates log files with timestamp every time i ran it creates new log files with current timestamp, so once i ran if task completed how to send log files automatically to outlook mail with in one program – lAkShMipythonlearner Jun 21 '23 at 07:26
0

You need a SMTP server to send Email. Check out the smtplib for Python

Philippe Lavoie
  • 2,583
  • 5
  • 25
  • 39