I need to send a message when my program is done running, but I also want to include variables such as how long the program took to run in the text.
Here is my code for the texting:
import smtplib
carriers = {
'att': '#mms.att.net',
'tmobile': ' #tmomail.net',
'verizon': '#vtext.com',
'sprint': '#page.nextel.com'
}
def send(message):
# Replace the number with your own, or consider using an argument\dict for multiple people.
to_number = 'xxxxxxxxxx{}'.format(carriers['verizon'])
auth = ('xxxxx', 'xxxx')
# Establish a secure session with gmail's outgoing SMTP server using your gmail account
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(auth[0], auth[1])
# Send text message through SMS gateway of destination number
server.sendmail(auth[0], to_number, message)
Obviously, I replaced my info with the xxx.
Now, to send my text I'm calling the function using:
found = 'The program is done!'
timetook = "Time took: %s (HOUR:MIN:SEC)" % timedelta(seconds=round(elapsed_time_secs))
send(found)
send(timetook)
It just sends blank texts for the timetook, but the program is done message works fine. How do I send the timetook?
The problem is that you aren't following the rules for SMTP. Below is the equivalent solution I wrote for my own use many years ago.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""SMS (short message service) functions."""
import logging
import smtplib
import sys
import rate_limiting
SMTP_GATEWAY = 'localhost'
FROM_ADDR = 'me#domain.us'
PHONE_NUMBER = '4081234567'
# T-Mobile SMS email gateway
# TO_ADDR = PHONE_NUMBER + '#tmomail.net'
# Verizon SMS email gateway
TO_ADDR = PHONE_NUMBER + '#vtext.com'
# Allow only three SMS messages per minute and five per hour.
short_term_rate_limiter = rate_limiting.SimpleRateLimiter(3, 60)
long_term_rate_limiter = rate_limiting.SimpleRateLimiter(5, 60 * 60)
def SendSms(msg, why=''):
"""Send a SMS message."""
short_term_rate_exceeded = short_term_rate_limiter()
long_term_rate_exceeded = long_term_rate_limiter()
if short_term_rate_exceeded or long_term_rate_exceeded:
logging.warning('SMS message rate exceeded, dropping msg: %s', msg)
return
smtp_conn = smtplib.SMTP(SMTP_GATEWAY)
hdrs = 'From: {}\r\nTo: {}\r\n\r\n'.format(FROM_ADDR, TO_ADDR)
if why:
hdrs += 'Subject: {}\r\n'.format(why[:20])
hdrs += "\r\n\r\n"
max_msg_len = 140 - 3 - min(20, len(why))
msg = hdrs + msg[:max_msg_len]
# Make sure the message has only ASCII characters.
msg = msg.encode('ascii', errors='replace').decode('ascii')
smtp_conn.sendmail(FROM_ADDR, [TO_ADDR], msg)
smtp_conn.quit()
if __name__ == '__main__':
SendSms(' '.join(sys.argv[1:]))
Related
I have a solution that distributes approx. 200 - 300 custom emails based on data and distributes personalized content. Based on dataframe, which consolidates and transform data, the unique list of recipients is identified on the top of that and via for loop it builds personalized content via SMTP server send the email. It works fine, however it started to fail lately after couple of iterations. It typically sends out 50% - 70% of emails and it fails then. So I need to restart it, but it keeps failing with the same error message:
SMTPRecipientsRefused Traceback (most recent call last) in 106 s = SMTP('SMTP server') --> 107 s.send_message(msg) 108 s.quit() 109 print('Email has been sent for ' + Recepient_name) d:\program files\alteryx\bin\miniconda3\envs\designerbasetools_venv\lib\smtplib.py in send_message(self, msg, from_addr, to_addrs, mail_options, rcpt_options) 968 g.flatten(msg_copy, linesep='\r\n') 969 flatmsg = bytesmsg.getvalue() --> 970 return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, 971 rcpt_options) 972 d:\program files\alteryx\bin\miniconda3\envs\designerbasetools_venv\lib\smtplib.py in sendmail(self, from_addr, to_addrs, msg, mail_options, rcpt_options) 879 if code == 421: 880 self.close() --> 881 raise SMTPRecipientsRefused(senderrs) 882 if len(senderrs) == len(to_addrs): 883 # the server refused all our recipients SMTPRecipientsRefused: {'': (421, b' Too many bad commands; closing connection')} (Tool Id: 34)
Any ideas, what's wrong there or how to fix it? It started to fail recently and it worked for couple of months without any issues. Can this be caused by some policy or settings on SMTP server? As it says it's been refused by SMTP server. I tried to delay every iteration by 2 seconds, but it did not help really.
Code that distributes the emails:
#for loop that generates and distributes emails to all recipients
for Recepient_name, Recepient_email in Recepients.itertuples(index=False):
df_recepients = df[df['Recepient Email'] == Recepient_email]
df_recepients = df_recepients[['ID','Status', 'Column 1', 'Columns 2']]
df_HTML = df_recepients.to_html(table_id = "table_score", index=False, escape=False, border = 0)
# replace automatically generated style for rows of table, which are aligned to right and cannot be disabled
df_HTML = df_HTML.replace('<tr style="text-align: right;">', "<tr>")
# load HTML template with variables to be replaced later on
with open(HTML_path, 'r') as file:
EmailTemplate = file.read()
EmailTemplate = EmailTemplate.replace("#Name#", Recepient_name)
msg = MIMEText(
Environment().from_string(
EmailTemplate
).render(), "html"
)
subject = "Shipments status of " + Recepient_name + " - " + datetime.datetime.now().strftime("%d %b %Y")
sender = "email#email.com"
recipient = Recepient_email
recipients_cc = sender
msg['Subject'] = subject
msg['From'] = sender
msg['X-Priority'] = '2'
msg['To'] = recipient
msg['Cc'] = recipients_cc
# Send the message via SMTP server.
s = SMTP('SMTP server')
s.send_message(msg)
s.quit()
print('Email has been sent for ' + Recepient_name)
I have method that sends an email and I want to make parametrize pytest test, but when I run my test it doesn't run and in logs it shows no tests ran. What's wrong with my test?
pytest scenario:
import pytest
import new_version
#pytest.mark.parametrize("email", ['my_email#gmail.com'])
def send_email(email):
new_version.send_mail(email)
method that sends email:
# Imports
import smtplib
import time
# Language
error_title = "ERROR"
send_error = "I'm waiting {idle} and I will try again."
send_error_mail = "Mail invalid"
send_error_char = "Invalid character"
send_error_connection_1_2 = "Connection problem..."
send_error_connection_2_2 = "Gmail server is down or internet connection is instabil."
login_browser = "Please log in via your web browser and then try again."
login_browser_info = "That browser and this software shood have same IP connection first time."
# Gmaild ID fro login
fromMail = "myemail#gmail.com"
fromPass = "pass"
# Some configurations
mailDelay = 15
exceptionDelay = 180
# SEND MAILS
def send_mail(email, thisSubject="Just a subject",
thisMessage="This is just a simple message..."):
# To ho to send mails
mailTo = [
email
]
# If still have mails to send
while len(mailTo) != 0:
sendItTo = mailTo[0] # Memorise what mail will be send it (debug purpose)
try:
# Connect to the server
server = smtplib.SMTP("smtp.gmail.com:587")
server.ehlo()
server.starttls()
# Sign In
server.login(fromMail, fromPass)
# Set the message
message = f"Subject: {thisSubject}\n{thisMessage}"
# Send one mail
server.sendmail(fromMail, mailTo.pop(0), message)
# Sign Out
server.quit()
# If is a problem
except Exception as e:
# Convert error in a string for som checks
e = str(e)
# Show me if...
if "The recipient address" in e and "is not a valid" in e:
print(f"\n>>> {send_error_mail} [//> {sendItTo}\n")
elif "'ascii'" in e and "code can't encode characters" in e:
print(f"\n>>> {send_error_char} [//> {sendItTo}\n")
elif "Please" in e and "log in via your web browser" in e:
print(f"\n>>> {login_browser}\n>>> - {login_browser_info}")
break
elif "[WinError 10060]" in e:
if "{idle}" in send_error:
se = send_error.split("{idle}");
seMsg = f"{se[0]}{exceptionDelay} sec.{se[1]}"
else:
seMsg = send_error
print(f"\n>>> {send_error_connection_1_2}\n>>> {send_error_connection_2_2}")
print(f">>> {seMsg}\n")
# Wait 5 minutes
waitTime = exceptionDelay - mailDelay
if waitTime <= 0:
waitTime = exceptionDelay
time.sleep(waitTime)
else:
if "{idle}" in send_error:
se = send_error.split("{idle}");
seMsg = f"{se[0]}{exceptionDelay} sec.{se[1]}"
else:
seMsg = send_error
print(f">>> {error_title} <<<", e)
print(f">>> {seMsg}\n")
# Wait 5 minutes
time.sleep(exceptionDelay)
# If are still mails wait before to send another one
if len(mailTo) != 0:
time.sleep(mailDelay)
logs:
platform darwin -- Python 3.7.5, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /Users/nikolai/Documents/Python/gmail/venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/nikolai/Documents/Python/gmail
collected 0 items
Unless you change the discovery prefixes for Pytest, test functions must be named test_*:
import pytest
import new_version
#pytest.mark.parametrize("email", ['my_email#gmail.com'])
def test_send_email(email):
new_version.send_mail(email)
I am new to python and my networking logics are at the beginner level. I have an HTTP server running in a VM and when I curl it from a different terminal on the same machine, I get the expected response. I am looking for a functionality where I can get the same response on my mobile device when I type the ip and port in the browser. My mobile device is connected to the same WiFi. Here's the server code:
import socket
MAX_PACKET = 32768
def recv_all(sock):
r'''Receive everything from `sock`, until timeout occurs, meaning sender
is exhausted, return result as string.'''
# dirty hack to simplify this stuff - you should really use zero timeout,
# deal with async socket and implement finite automata to handle incoming data
prev_timeout = sock.gettimeout()
try:
sock.settimeout(0.01)
rdata = []
while True:
try:
rdata.append(sock.recv(MAX_PACKET))
except socket.timeout:
return ''.join(rdata)
# unreachable
finally:
sock.settimeout(prev_timeout)
def normalize_line_endings(s):
r'''Convert string containing various line endings like \n, \r or \r\n,
to uniform \n.'''
return ''.join((line + '\n') for line in s.splitlines())
def run():
r'''Main loop'''
# Create TCP socket listening on 10000 port for all connections,
# with connection queue of length 1
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, \
socket.IPPROTO_TCP)
server_sock.bind(('10.0.2.15',80))
server_sock.listen(1)
while True:
# accept connection
client_sock, client_addr = server_sock.accept()
# headers and body are divided with \n\n (or \r\n\r\n - that's why we
# normalize endings). In real application usage, you should handle
# all variations of line endings not to screw request body
request = normalize_line_endings(recv_all(client_sock)) # hack again
request_head, request_body = request.split('\n\n', 1)
# first line is request headline, and others are headers
request_head = request_head.splitlines()
request_headline = request_head[0]
# headers have their name up to first ': '. In real world uses, they
# could duplicate, and dict drops duplicates by default, so
# be aware of this.
request_headers = dict(x.split(': ', 1) for x in request_head[1:])
# headline has form of "POST /can/i/haz/requests HTTP/1.0"
request_method, request_uri, request_proto = request_headline.split(' ', 3)
response_body = [
'<html><body><h1>Hello, world!</h1>',
'<p>This page is in location %(request_uri)r, was requested ' % locals(),
'using %(request_method)r, and with %(request_proto)r.</p>' % locals(),
'<p>Request body is %(request_body)r</p>' % locals(),
'<p>Actual set of headers received:</p>',
'<ul>',
]
for request_header_name, request_header_value in request_headers.iteritems():
response_body.append('<li><b>%r</b> == %r</li>' % (request_header_name, \
request_header_value))
response_body.append('</ul></body></html>')
response_body_raw = ''.join(response_body)
# Clearly state that connection will be closed after this response,
# and specify length of response body
response_headers = {
'Content-Type': 'text/html; encoding=utf8',
'Content-Length': len(response_body_raw),
'Connection': 'close',
}
response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in \
response_headers.iteritems())
# Reply as HTTP/1.1 server, saying "HTTP OK" (code 200).
response_proto = 'HTTP/1.1'
response_status = '200'
response_status_text = 'OK' # this can be random
# sending all this stuff
client_sock.send('%s %s %s' % (response_proto, response_status, \
response_status_text))
client_sock.send(response_headers_raw)
client_sock.send('\n') # to separate headers from body
client_sock.send(response_body_raw)
# and closing connection, as we stated before
client_sock.close()
run()
Here's the response when I run curl from a different terminal on the same VM.
I want to ping it from my mobile device connected to the same WiFi. Thank you!
Hello Guys i am trying to learn how to make a twitch bot for my friends' channel they streams regulary and sometimes i join them.
Now i was able to make the bot join to the chat room but i couldn't figure out administration part so the bot suppoused to timeout any body uses the word "swear"
instead i get this error:
tmi: :tmi.twitch.tv 001 wasddabulyuasede_bot :Welcome, GLHF!
:tmi.twitch.tv 002 wasddabulyuasede_bot :Your host is tmi.twitch.tv
:tmi.twitch.tv 003 wasddabulyuasede_bot :This server is rather new
:tmi.twitch.tv 004 wasddabulyuasede_bot :-
:tmi.twitch.tv 375 wasddabulyuasede_bot :-
:tmi.twitch.tv 372 wasddabulyuasede_bot :You are in a maze of twisty passages, all alike.
:tmi.twitch.tv 376 wasddabulyuasede_bot :>
wasddabulyuasede_bot: :wasddabulyuasede_bot!wasddabulyuasede_bot#wasddabulyuasede_bot.tmi.twitch.tv JOIN #wlrs
_
:wasddabulyuasede_bot.tmi.twitch.tv 353 wasddabulyuasede_bot = #wlrs_ :wasddabulyuasede_bot
:wasddabulyuasede_bot.tmi.twitch.tv 366 wasddabulyuasede_bot #wlrs_ :End of /NAMES list
wlrs_: swear
Traceback (most recent call last):
File "Bot.py", line 57, in <module>
timeout(s,username,10)
File "Bot.py", line 33, in timeout
chat(sock, ".timeout {}".format(user, secs))
File "Bot.py", line 14, in chat
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg_encoded))
TypeError: a bytes-like object is required, not 'str'
CODE
#cfg.py
#oauth key has been removed
HOST = "irc.chat.twitch.tv"
PORT = 6667
PASS = "oauth:xxxxxxxxxxxxxxxxxxxx"
NICK = "wasddabulyuasede_bot"
CHAN = "#wlrs_"
RATE = (20/30)
PATT = [
r"swear"
]
Bot.py
from cfg import HOST, PORT, PASS, NICK, CHAN, RATE, PATT
import cfg
import socket
import re
import time
def chat(sock, msg):
"""
Send a chat message to the server.
Keyword arguments:
sock -- the socket over which to send the message
msg -- the message to be sent
"""
msg_encoded = msg.encode("utf-8")
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg_encoded))
# def ban(sock, user):
# """
# Ban a user from the current channel.
# Keyword arguments:
# sock -- the socket over which to send the ban command
# user -- the user to be banned
# """
# chat(sock, ".ban {}".format(user))
#
def timeout(sock, user, secs=600):
"""
Time out a user for a set period of time.
Keyword arguments:
sock -- the socket over which to send the timeout command
user -- the user to be timed out
secs -- the length of the timeout in seconds (default 600)
"""
chat(sock, ".timeout {}".format(user, secs))
# ----- network functions -----
s = socket.socket()
s.connect((HOST, PORT))
s.send("PASS {} \r\n".format(PASS).encode("utf-8"))
s.send("NICK {} \r\n".format(NICK).encode("utf-8"))
s.send("JOIN {} \r\n".format(CHAN).encode("utf-8"))
# pattern we are looking for
CHAT_MSG=re.compile(r"^:\w+!\w+#\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")
while True:
response = s.recv(1024).decode("utf-8")
if response == "PING :tmi.twitch.tv\r\n":
s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
username = re.search(r"\w+", response).group(0) # return the entire match
message = CHAT_MSG.sub("", response)
print(username + ": " + message)
for pattern in cfg.PATT:
if re.match(pattern,message):
timeout(s,username,10)
break
time.sleep(1/cfg.RATE)
A string is an abstraction, representing a sequence of unicode codepoints.
To turn a string into a sequence of bytes, you need to encode your string, aka decide on how you want to represent your text on the wire. For Twitch, use UTF-8:
full_msg = "PRIVMSG #{} :{}".format(cfg.CHAN, msg)
msg_encoded = full_msg.encode("utf-8")
sock.send(msg_encoded)
Code below:
import smtplib
content = ["zero","one", "two", "three", "four", "five", "six"]
def email (content):
FROMADDR = "SENDER#gmail.com"
LOGIN = FROMADDR
PASSWORD = "PASSWORD"
TOADDRS = ["SEND TO"]
SUBJECT = "Test"
for term in content: #LOOP
msg = ("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n"
% (FROMADDR, ", ".join(TOADDRS), SUBJECT) )
msg += term + "\r\n"
server = smtplib.SMTP('smtp.gmail.com', 587)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.login(LOGIN, PASSWORD)
server.sendmail(FROMADDR, TOADDRS, msg)
server.quit()
email(content)
This program iterates through the list and emails each item, one at a time.
How can I have the program email an item on the list at certain times of day every week until it send all items on the list?
(I am asking this question related to this example because it is easier)
Let's say I want to email one item at a time until all items are sent. The first item at 2pm on Monday, the second item at 4pm on Monday, the third item at 7 pm on Tuesday, and the fourth item at 8pm Friday. Then I want the program to send the next four items at those times every week until it sends all the items on the list. So I should be getting the next item on the list at those times.
I know linux has a program that can run a program at specific times, but if I use that it will send the whole list each time not the next item.
The python sleep() function will not work because the times I want it to email are not in constant intervals.
Set cron to run at the times you want messages to send.
Keep a file on disk that contains the list, along with a place keeper string.
Each time the script runs, open the file, do what you need to do, write the file back out.
a "green" & resources very economic approach ( no cron, no re-reading anything many times again )
this is a smart-scheduling problem solution, it leaves on your responsibility to create correct the smtp-sending handler and iterator, not repairing the code above.
import Tkinter as tk
import time
root = tk.Tk()
aNextSendingTIME = aFunctionToGetNextSendingTIME_asSECONDs() # .SET <WHEN_NEXT>
root.title( time.ctime( aNextSendingTIME ) ) # .GUI show ...
root.lower() # .GUI minimize inTaskBAR
# ---------
# SCHEDULER
# ---------
root.after( 1000 * ( aNextSendingTIME # .GOT <WHEN_NEXT>
- time.time() # .SUB <NOW>
), # .MUL asMSECs
sendNextOneEmailFUNCTION # .SET HANDLER
)
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ YOUR APPLICATION CODE \/\/\/\/\/\/\/\
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ YOUR APPLICATION CODE \/\/\/\/\/\/\/\
Then:
def sendNextOneEmailFUNCTION( ):
# -----------------------------------------<your SMTP-handling code here>---
# -----------------------------------------<your SMTP-handling code here>---
# PLUS:
# calc / set the next sending after aNextPointInTime_asMilliseconds DISTANCE
aNextSendingTIME = aFunctionToGetNextSendingTIME_asSECONDs() # .GET <WHEN_NEXT>
aNextPointInTime_asMilliseconds = 1000
* ( aNextSendingTIME
- time.time()
)
root.title( time.ctime( aNextSendingTIME ) ) # .GUI update inTaskBAR
# --------------
# SCHEDULE AGAIN
# --------------
root.after( aNextPointInTime_asMilliseconds, # .SET <WHEN_NEXT>
sendNextOneEmailFUNCTION # .SET HANDLER
)
return
Finally, to set dates, do whatever input you prefer -- be it via a command-line <filname> or coded asList = [ "2014-08-21 12:00", "2014-08-21 17:30", ... ]
def aFunctionToGetNextSendingTIME_asSECONDs():
#
# solve data adaptation from a selected data-source, be it <asList> or other
#
aNextSendingTIME_asSECONDs = ...
return ( aNextSendingTIME_asSECONDs )