I am trying to send an email every so often from python. My situation is the next:
I have a database that receives sensor values such as temperature, humidity, pressure, etc. So the database is updated every so often, in my case data is sent every 1 minute to the database, what I try to do is that when the temperature passes a certain value, for example 26 ° C, sending mail stops for example 10 or 20 minutes and send another one in case the temperature stays above 26. I managed to send the mail, but my situation is that it does not stop and sends mails without stopping while the value of the temperature is above 26 ° C.
This is the code:
dataSQL = []
sql_conn = MySQLdb.connect('localhost', 'root', 'pass', 'DB')
cursor = sql_conn.cursor()
cursor.execute("SELECT value,timestamp FROM sensorParser where sensor='TC'")
rows = cursor.fetchall()
for row in rows:
dataSQL.append(list(row))
labels = ['value','timestamp']
df = pd.DataFrame.from_records(dataSQL, columns=labels)
X = df['timestamp']
Y = df['value'].astype(float)
if (float(df['value'][0]) > 26):
email = 'email1#gmail.com'
password = 'pass'
send_to_email = 'email2#gmail.com'
subject = 'ALERTA!!!! SENSORES'
message = 'Los valores de las variables criticas han superado el limite'
file_location = 'C:\\Users\\User\\Desktop\\prograpython\\image.jpg'
msg = MIMEMultipart()
msg['From'] = email
msg['To'] = send_to_email
msg['Subject'] = subject
msg.attach(MIMEText(message, 'plain'))
filename = os.path.basename(file_location)
attachment = open(file_location, "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(email, password)
text = msg.as_string()
server.sendmail(email, send_to_email, text)
server.quit()
Regards.
You can import time into the program and save the time value when the email is sent. Then you can add a check wether ten minutes have passed since the time was saved into the if-statement like this:
import time
timestamp = 0
# ... your code
if (float(df['value'][0]) > 26) and (timestamp == 0 or time.time() - timestamp > 600):
timestamp = time.time()
# ... your code
time.time() outputs the so-called unix time, which is the number of seconds that have passed since the 1st of January 1970. In the new expression for the if-statement you also check wether more than 600 seconds have passed since you last called the code in the statement, you can change the number of seconds to fit your needs.
Feel free to ask if any further questions should arise.
PS: Please limit the code you share to what is necessary, it makes the question more friendly-looking and easier to read :)
Related
I'm trying to send and email based on High temperature or humidity but i cant figure out how to add this. Its my first time using DHT22 with Raspberry Pi so not sure how to structure my code.
I've tried a variety of codes others have suggested but they either no longer work on Python 3 (originally Python 2 - depreciated), or the code I've written just doesn't do anything except monitor and log with no email on high temp.
My original coding so far is this:
import os
import time
from time import sleep
from datetime import datetime
import Adafruit_DHT
file = open("/home/pi/TempHumLog.csv", "a")
if os.stat("/home/pi/TempHumLog.csv").st_size == 0:
file.write("Date,Time,Temperature,Humidity\n")
while True:
DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 4
temperature, humidity = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
file.write("{0},{1},{3:0.2f}*C,{2:0.2f}%rh\n".format(time.strftime("%d/%m/%y"), time.strftime("%H:%M:%S"), temperature, humidity))
file.flush()
print("{0},{1},{3:0.2f}*C,{2:0.2f}%rh\n".format(time.strftime("%d/%m/%y"), time.strftime("%H:%M:%S"), temperature, humidity))
time.sleep(5)
import smtplib
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'example#gmail.com' #change this to match your gmail account
GMAIL_PASSWORD = 'example pw' #change this to match your gmail password
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if temperature > 24:
sendTo = 'example#gmail.com'
emailSubject = "High Temp!"
emailContent = "<br>A High Temp has Activated At: " + time.ctime() + "<br><br>Check The Room Temperature Levels"
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
elif temperature < 23:
sendTo = 'example#gmail.com'
emailSubject = "Room Temp Healthy"
emailContent = "High Room Temp Alarm Has Cleared At: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(5)
At this time, no errors come through the terminal but it doesn't send any email. I've tried adding something like this:
instance = dht22.DHT22(pin=4)
while True:
result = instance.read()
tempHI = 26
tempLOW = 19
if (result.temperature) > tempHI:
**Send Email Script**
But no luck!
Any ideas how i can get the high temperature to trigger the email?
I have this code that sends out emails individually through gmail from a list of emails in an excel file. I just want to know how to make the bot pause for 60 seconds after it's sent 50 emails and then continue with the list after the 60 seconds is up. I'm just trying to be safe with gmails daily limits.
import smtplib
import openpyxl as xl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
username = str(input('Your Username:' ))
password = str(input('Your Password:' ))
From = username
Subject = 'Free Beats and Samples For You :)'
wb = xl.load_workbook(r'C:\Users\19548\Documents\EMAILS.xlsx')
sheet1 = wb.get_sheet_by_name('EMAIL TEST - Sheet1')
names = []
emails = []
for cell in sheet1['A']:
emails.append(cell.value)
for cell in sheet1['B']:
names.append(cell.value)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(username, password)
for i in range(len(emails)):
msg = MIMEMultipart()
msg['From'] = username
msg['To'] = emails[i]
msg['Subject'] = Subject
text = '''
{}
'''.format(names[i])
msg.attach(MIMEText(text, 'plain'))
message = msg.as_string()
server.sendmail(username, emails[i], message)
print('Mail sent to', emails[i])
server.quit()
print('All emails sent successfully!')
You can use time.sleep() to wait a given number of seconds, and you can keep track of the number of emails sent using a variable that gets incremented with each iteration of the loop. Since you're already working with both the emails themselves and their indices, you can simplify this counting by using Python's enumerate function, which gives you both the next value and its corresponding index:
for index, email in enumerate(emails, start=1):
msg = <...>
message = msg.as_string()
server.sendmail(username, email, message)
if index % 50 == 0:
time.sleep(60)
if(your_value%50==0):
time.sleep(60)
I am working on a simple program to email me the weather in my city each morning. At the moment, it works, but only once. Using a while loop works, but since I have it set to,
while time == 0600:
send my mail etc
Now obviously, that makes it so for the entirety of that minute, I get spammed with mail. So I need to figure out a way for something to happen once, every 24 hours.
Here is my full code (currently only working once, until I restart it).
import smtplib, pywapi, datetime
weather = True
loopmsg = True
loopmsg1 = True
def send():
loopmsg = True
loopmsg1 = True
global weather
while weather == True:
if loopmsg == True:
print('Initial Loop Initiated')
loopmsg = False
time = datetime.datetime.now()
time = str(time)
time = time[11:]
time = time[:-10]
time = time.replace(":", "")
time = int(time)
fromaddr = 'xxx'
toaddrs = 'xxx'
while time == 0600:
print('Time is correct')
weather_com_result = pywapi.get_weather_from_weather_com('ASXX0075')
msg = "It is " + weather_com_result['current_conditions']['text'].lower() + " and " + weather_com_result['current_conditions']['temperature'] + "°C in Your City."
msg = msg.encode('utf-8')
# Credentials (if needed)
username = 'xxx'
password = 'xxx'
# The actual mail send
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
print('Sent')
#weather = False
#while weather == False:
# if loopmsg1 == True:
# print('Second Loop Initiated')
# loopmsg1 = False
# while time > 0600:
# send()
send()
First of all, you're running a script all day long for it to do something only once a day. This is illogical. You should schedule a task on your OS (Win, Linux, Mac - they all have a way to schedule tasks) so that your script is activated at 6h every day; and remove the time condition inside your script.
If you want to get fancy, create a Telegram bot and have it send you a message any time you want, on your phone, for the location you specify right then.
The script however is easy to fix. You're using that while loop as an if. Just add a variable that will make it send an e-mail only once.
if time == 0500:
send_email = True
if send_email and time == 0600:
print('Time is correct')
send_email = False
weather_com_result = pywapi.get_weather_from_weather_com('ASXX0075')
....
Why not just have a break statement right after you send the email? This just causes you to break out of the loop. Then it will execute the rest of the program.
while time == 0600:
print('Time is correct')
weather_com_result = pywapi.get_weather_from_weather_com('ASXX0075')
msg = "It is " + weather_com_result['current_conditions']['text'].lower() + " and " + weather_com_result['current_conditions']['temperature'] + "°C in Your City."
msg = msg.encode('utf-8')
# Credentials (if needed)
username = 'xxx'
password = 'xxx'
# The actual mail send
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
print('Sent')
break
My email program is emailing each line of the message as a separate email, i would like to know how to send all of the message in one email, when the email is sent the program will return to the beginning.
import smtplib
from email.mime.text import MIMEText
a = 1
while a == 1:
print " "
To = raw_input("To: ")
subject = raw_input("subject: ")
input_list = []
print "message: "
while True:
input_str = raw_input(">")
if input_str == "." and input_list[-1] == "":
break
else:
input_list.append(input_str)
for line in input_list:
# Create a MIME text message and populate its values
msg = MIMEText(line)
msg['Subject'] = subject
msg['From'] = '123#example.com'
msg['To'] = To
server = smtplib.SMTP_SSL('server', 465)
server.ehlo()
server.set_debuglevel(1)
server.ehlo()
server.login('username', 'password')
# Send a properly formatted MIME message, rather than a raw string
server.sendmail('user#example.net', To, msg.as_string())
server.close()
(the part that takes multiple lines was made with the help Paul Griffiths, Multiline user input python)
for line in input_list:
# Create a MIME text message and populate its values
msg = MIMEText(line)
You are calling server.sendmail in this loop.
Build your entire msg first (in a loop), THEN add all of your headers and send your message.
I am interested to trigger a certain action upon receiving an email from specific
address with specific subject. In order to be able to do so I need to implement
monitoring of my mailbox, checking every incoming mail (in particular, i use gmail).
what is the easiest way to do that?
Gmail provides the ability to connect over POP, which you can turn on in the gmail settings panel. Python can make connections over POP pretty easily:
import poplib
from email import parser
pop_conn = poplib.POP3_SSL('pop.gmail.com')
pop_conn.user('username')
pop_conn.pass_('password')
#Get messages from server:
messages = [pop_conn.retr(i) for i in range(1, len(pop_conn.list()[1]) + 1)]
# Concat message pieces:
messages = ["\n".join(mssg[1]) for mssg in messages]
#Parse message intom an email object:
messages = [parser.Parser().parsestr(mssg) for mssg in messages]
for message in messages:
print message['subject']
pop_conn.quit()
You would just need to run this script as a cron job. Not sure what platform you're on so YMMV as to how that's done.
Gmail provides an atom feed for new email messages. You should be able to monitor this by authenticating with py cURL (or some other net library) and pulling down the feed. Making a GET request for each new message should mark it as read, so you won't have to keep track of which emails you've read.
While not Python-specific, I've always loved procmail wherever I could install it...!
Just use as some of your action lines for conditions of your choice | pathtoyourscript (vertical bar AKA pipe followed by the script you want to execute in those cases) and your mail gets piped, under the conditions of your choice, to the script of your choice, for it to do whatever it wants -- hard to think of a more general approach to "trigger actions of your choice upon receipt of mails that meet your specific conditions!! Of course there are no limits to how many conditions you can check, how many action lines a single condition can trigger (just enclose all the action lines you want in { } braces), etc, etc.
People seem to be pumped up about Lamson:
https://github.com/zedshaw/lamson
It's an SMTP server written entirely in Python. I'm sure you could leverage that to do everything you need - just forward the gmail messages to that SMTP server and then do what you will.
However, I think it's probably easiest to do the ATOM feed recommendation above.
EDIT: Lamson has been abandoned
I found a pretty good snippet when I wanted to do this same thing (and the example uses gmail). Also check out the google search results on this.
I recently solved this problem by using procmail and python
Read the documentation for procmail. You can tell it to send all incoming email to a python script like this in a special procmail config file
:0:
| ./scripts/ppm_processor.py
Python has an "email" package available that can do anything you could possibly want to do with email. Read up on the following ones....
from email.generator import Generator
from email import Message
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.mime.multipart import MIMEMultipart
https://developers.google.com/gmail/gmail_inbox_feed
Says you have to have a corporate Gmail, but I have come to find that you can read Gmail free versions without issues. I use this code to get my blood pressure results I email or text to a gmail address.
from email.header import decode_header
from datetime import datetime
import os
import pandas as pd
import plotly.graph_objs as go
import plotly
now = datetime.now()
dt_string = now.strftime("%Y.%m.%d %H:%M:%S")
print("date_time:", dt_string)
email_account = '13123#gmail.com'
email_password = '131231231231231231312313F'
email_server = 'imap.gmail.com'
email_port = 993
accept_emails_from = {'j1231312#gmail.com', '1312312#chase.com', '13131231313131#msg.fi.google.com'}
verbose = True
def get_emails():
email_number = 0
local_csv_data = ''
t_date = None
t_date = None
t_systolic = None
t_diastolic = None
t_pulse = None
t_weight = None
try:
mail = imaplib.IMAP4_SSL(email_server)
email_code, email_auth_status = mail.login(email_account, email_password)
if verbose:
print('[DEBUG] email_code: ', email_code)
print('[DEBUG] email_auth_status: ', email_auth_status)
mail.list()
mail.select('inbox')
# (email_code, messages) = mail.search(None, 'ALL')
(email_code, messages) = mail.search(None, '(UNSEEN)') # only get unread emails to process.
subject = None
email_from = None
for email_id in messages[0].split():
email_number += 1
email_code, email_data = mail.fetch(email_id, '(RFC822)')
for response in email_data:
if isinstance(response, tuple): # we only want the tuple ,the bytes is just b .
msg = email.message_from_bytes(response[1])
content_type = msg.get_content_type()
subject, encoding = decode_header(msg["Subject"])[0]
subject = str(subject.replace("\r\n", ""))
if isinstance(subject, bytes):
subject = subject.decode(encoding)
email_from, encoding = decode_header(msg.get("From"))[0]
if isinstance(email_from, bytes):
email_from = email_from.decode(encoding)
if content_type == "text/plain":
body = msg.get_payload(decode=True).decode()
parse_data = body
else:
parse_data = subject
if '>' in email_from:
email_from = email_from.lower().split('<')[1].split('>')[0]
if email_from in accept_emails_from:
parse_data = parse_data.replace(',', ' ')
key = 0
for value in parse_data.split(' '):
if key == 0:
t_date = value
t_date = t_date.replace('-', '.')
if key == 1:
t_time = value
if ':' not in t_time:
numbers = list(t_time)
t_time = numbers[0] + numbers[1] + ':' + numbers[2] + numbers[3]
if key == 2:
t_systolic = value
if key == 3:
t_diastolic = value
if key == 4:
t_pulse = value
if key == 5:
t_weight = value
key += 1
t_eval = t_date + ' ' + t_time
if verbose:
print()
print('--------------------------------------------------------------------------------')
print('[DEBUG] t_eval:'.ljust(30), t_eval)
date_stamp = datetime.strptime(t_eval, '%Y.%m.%d %H:%M')
if verbose:
print('[DEBUG] date_stamp:'.ljust(30), date_stamp)
print('[DEBUG] t_systolic:'.ljust(30), t_systolic)
print('[DEBUG] t_diastolic:'.ljust(30), t_diastolic)
print('[DEBUG] t_pulse:'.ljust(30), t_pulse)
print('[DEBUG] t_weight:'.ljust(30), t_weight)
new_data = str(date_stamp) + ',' + \
t_systolic + ',' + \
t_diastolic + ',' + \
t_pulse + ',' + \
t_weight + '\n'
local_csv_data += new_data
except Exception as e:
traceback.print_exc()
print(str(e))
return False, email_number, local_csv_data
return True, email_number, local_csv_data
def update_csv(local_data):
""" updates csv and sorts it if there is changes made. """
uniq_rows = 0
if os.name == 'posix':
file_path = '/home/blood_pressure_results.txt'
elif os.name == 'nt':
file_path = '\\\\uncpath\\blood_pressure_results.txt'
else:
print('[ERROR] os not supported:'.ljust(30), os.name)
exit(911)
if verbose:
print('[DEBUG] file_path:'.ljust(30), file_path)
column_names = ['00DateTime', 'Systolic', 'Diastolic', 'Pulse', 'Weight']
if not os.path.exists(file_path):
with open(file_path, 'w') as file:
for col in column_names:
file.write(col + ',')
file.write('\n')
# append the new data to file.
with open(file_path, 'a+') as file:
file.write(local_data)
# sort the file.
df = pd.read_csv(file_path, usecols=column_names)
df_sorted = df.sort_values(by=["00DateTime"], ascending=True)
df_sorted.to_csv(file_path, index=False)
# remove duplicates.
file_contents = ''
with open(file_path, 'r') as file:
for row in file:
if row not in file_contents:
uniq_rows += 1
print('Adding: '.ljust(30), row, end='')
file_contents += row
else:
print('Duplicate:'.ljust(30), row, end='')
with open(file_path, 'w') as file:
file.write(file_contents)
return uniq_rows
# run the main code to get emails.
status, emails, my_data = get_emails()
print('status:'.ljust(30), status)
print('emails:'.ljust(30), emails)
# if the new emails received then sort the files.
csv_rows = update_csv(my_data)
print('csv_rows:'.ljust(30), csv_rows)
exit(0)