Azure communication services send email - python

I am using azure communication services in my react app to send email.
But I want to send bulk messages via a text file or an excel file
import time
from azure.communication.email import EmailClient, EmailContent, EmailAddress, EmailMessage, EmailRecipients
def main():
try:
connection_string = "<ACS_CONNECTION_STRING>"
client = EmailClient.from_connection_string(connection_string)
sender = "<SENDER_EMAIL>"
content = EmailContent(
subject="Test email from Python",
plain_text="This is plaintext body of test email.",
html= "<html><h1>This is the html body of test email.</h1></html>",
)
recipient = EmailAddress(email="<RECIPIENT_EMAIL>", display_name="<RECIPIENT_DISPLAY_NAME>")
message = EmailMessage(
sender=sender,
content=content,
recipients=EmailRecipients(to=[recipient])
)
response = client.send(message)
if (not response or response.message_id=='undefined' or response.message_id==''):
print("Message Id not found.")
else:
print("Send email succeeded for message_id :"+ response.message_id)
message_id = response.message_id
counter = 0
while True:
counter+=1
send_status = client.get_send_status(message_id)
if (send_status):
print(f"Email status for message_id {message_id} is {send_status.status}.")
if (send_status.status.lower() == "queued" and counter < 12):
time.sleep(10) # wait for 10 seconds before checking next time.
counter +=1
else:
if(send_status.status.lower() == "outfordelivery"):
print(f"Email delivered for message_id {message_id}.")
break
else:
print("Looks like we timed out for checking email send status.")
break
except Exception as ex:
print(ex)
main()
How to solve this issue?
I tried to get emails from a text file, but it failed for me

Related

How can I fix this python socket problem? (solved)

I've been trying to create a chat room using python and the socket module, but I have run into a bug which I don't know how to fix.
At the moment, when I send a message through one of the clients, the message will be outputted again in the terminal of the person who sent it. E.g. column 3, rows 1 & 3 (column 3 is Jim's).
This is the code I wrote for the clients (Re. receiving/sending data):
# Receive data from server
def receive_data():
while True:
try:
mes = client.recv(1024).decode('ascii')
# If the message is 'name', send name to server
if mes == 'name':
client.send(name.encode('ascii'))
# If the message comes from the same person, don't show it
elif name == mes[0:(len(name)+1)]:
pass
# Otherwise it will print the message
else:
print(mes)
except:
# Close the connection
print(f"{colours.Colours.red}An error occurred!{colours.Colours.end}")
client.close()
break
# Send data to server
def send_data():
while True:
message_to_send = input("You : ")
mes = f"\n{name} : {message_to_send}"
client.send(mes.encode('ascii'))
I wrote this for the server. After it was all setup, the receive function was run. By the way, the protocol is TCP.
# Handling clients
def handle_clients(client):
while True:
try:
# Broadcasting messages
mes = client.recv(1024)
broadcast(mes)
except:
# Removing clients
name = clients[client]
broadcast(f"{colours.Colours.red}{name} has left!{colours.Colours.end}".encode('ascii'))
del clients[client]
break
# Recieving data
def recieve():
while True:
# Accept connection
conn, addr = server.accept()
print(f"{colours.Colours.green}Connected with {addr}!{colours.Colours.end}")
# Request & store name
conn.send("NAME".encode('ascii'))
name = conn.recv(1024).decode('ascii')
clients.update({conn : name})
# Start handling thread for client
thread = threading.Thread(target=handle_clients, args=(conn,))
thread.start()
How can I solve this?
Sam
SOLVED
After going over it a bit, I figured out what the problem was. It was more about the server relaying it, instead of the client.
This is my new server code (that I changed):
# If the name of the sender is the same as in the message, return True
def check_name(name, client_name):
client_name = client_name[0]
if name == client_name:
return True
else:
return False
# Send message to all clients
def broadcast(message, ignore=False):
for client, name in clients.items():
if not ignore:
client.send(message.encode('ascii'))
else:
if check_name(ignore, name):
pass
else:
client.send(message.encode('ascii'))
# Handling clients
def handle_clients(client):
while True:
try:
# Decode message
mes = client.recv(1024).decode('ascii')
if not mes:
break
# Get the name of the sender
name = mes.split(" : ")
name = name[0]
name = name.replace('\n', '')
name = name.strip()
mes = mes.replace('\n', '')
# Broadcast
broadcast(mes, ignore=name)
except:
# Removing clients
name = clients[client]
broadcast(f"{colours.Colours.red}{name} has left!{colours.Colours.end}".encode('ascii'))
del clients[client]
break
This is my new client code:
# Recieve data from server
def receive():
while True:
try:
mes = client.recv(1024).decode('ascii')
# If the message is 'NAME', send the name to server
if mes == 'NAME':
client.send(name.encode('ascii'))
# Otherwise it will print the message
else:
print(mes)
except:
# Close the connection
print(f"{colours.Colours.red}An error occurred!{colours.Colours.end}")
client.close()
break
# Send data to server
def send():
while True:
message_to_send = input("You : ")
mes = f"\n{name} : {message_to_send}"
client.send(mes.encode('ascii'))

Python Gmail API : How to batch download of email attachments and emails?

I have the below code, which downloads a Gmail email and its attachments. It returns its attachments.
def gmailAPIDownloadAttachments(self, messageID, userID="me"):
try:
service = self.gmailAPIService
self.GLogger.info("Attempting to download attachments from messageID (" +str(messageID)+ ")")
message = self.gmailAPIGetFullMessage(messageID, userID=userID)
if message is False:
self.GLogger.error("Failed to extract message (" +str(messageID)+ ") for downloading attachments")
return False
attachmentList = list()
payload = message['payload']
if 'parts' in payload:
parts = payload['parts']
for part in parts:
if part['filename']:
if 'data' in part['body']:
data = part['body']['data']
else:
att_id = part['body']['attachmentId']
att = service.users().messages().attachments().get(userId=userID, messageId=messageID, id=att_id).execute()
data = att['data']
file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
filename = part['filename']
extSearch = filename.find('.')
if extSearch == -1:
ext = ""
partFileName = filename[0:extSearch]
else:
ext = filename[extSearch+1:]
partFileName = filename[0:extSearch]
theAttachment = Attachment(filename,partFileName, ext, file_data)
attachmentList.append(theAttachment)
self.GLogger.info("Successfully downloaded attachments from messageID (" +str(messageID)+ ")")
return(attachmentList)
except:
self.GLogger.error("Encountered an error while attempting to download email attacments from messageID (" +str(messageID)+ ")")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
I understand how to convert fetching messages into batching. For example, this is how one could batch-fetch messages:
from apiclient.http import BatchHttpRequest
import json
batch = BatchHttpRequest()
#assume we got messages from Gmail query API
for message in messages:
batch.add(service.users().messages().get(userId='me', id=message['id'],
format='raw'))
batch.execute()
for request_id in batch._order:
resp, content = batch._responses[request_id]
message = json.loads(content)
#handle your message here, like a regular email object
However, the attachments aspect seem to have logic and other possible fetches such as in this part:
att_id = part['body']['attachmentId']
att = service.users().messages().attachments().get(userId=userID, messageId=messageID, id=att_id).execute()
data = att['data']
How can I effectively batch both fetching the message and its attachments? I would like to be able to quickly fetch many emails at once.

How to deal with error when mails are read

The script is first doing it job
find the message with specific subject
send a message to the sender
copy the message to folder 'answered'
delete the message
sleep for 1min and repeat
mail.select()
status, messages = mail.select("INBOX")
n = int(str(messages[0], 'utf-8'))
messages = int(messages[0])
for i in range(messages, messages-n,-1):
res, msg = mail.fetch(str(i), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
# parse a bytes email into a message object
msg = email.message_from_bytes(response[1])
Sub, encoding = decode_header(msg.get("Subject"))[0] # Error is about this line
Sub=Sub.decode((encoding))
if Sub == pat:
fro, encoding = decode_header(msg.get("From"))[0]
if isinstance(fro, bytes):
fro = fro.decode(encoding)
# if s == 0:
# time.sleep(60)
# mai_load(1)
print("From:", fro)
send_mail(fro)
mail.copy(str(i), 'praca')
mail.store(str(i), '+FLAGS', '\\Deleted')
print("=" * 100)
time.sleep(60)
mai_load(0)
And here is the problem, messages are mark as read and when the scripts connects again I'm receiving an error:
line 99, in mai_load
Sub, encoding = decode_header(msg.get("Subject"))[0]
File "/usr/lib/python3.8/email/header.py", line 80, in decode_header
if not ecre.search(header):
TypeError: expected string or bytes-like object
Try my lib: https://github.com/ikvk/imap_tools
from imap_tools import MailBox, AND, MailMessageFlags
with MailBox('imap.mail.com').login('test#mail.com', 'pwd', 'INBOX') as mailbox:
# get list of email senders from INBOX folder
senders = [msg.from_ for msg in mailbox.fetch()]
# FLAG unseen messages in current folder (INBOX) as Flagged
mailbox.flag(mailbox.fetch(AND(seen=False)), [MailMessageFlags.FLAGGED], True)

Reply to specific email and delete

I want the script response for email with specific Subject and then delete that email.
The script is doing one job which is responding to the email but I'm struggling with deleting that email, I'm not sure if I'm doing it even correctly: mail.store(response[1], '+FLAGS', '\Deleted') gives an error: imaplib.error: STORE command error: BAD [b'Could not parse command']
mail.select()
status, messages = mail.select("INBOX")
n = int(str(messages[0], 'utf-8'))
messages = int(messages[0])
for i in range(messages, messages-n,-1):
res, msg = mail.fetch(str(i), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
# parse a bytes email into a message object
msg = email.message_from_bytes(response[1])
Sub, encoding = decode_header(msg.get("Subject"))[0]
if isinstance(Sub, bytes): # check the subject
Sub=Sub.decode((encoding))
if Sub == pat:
fro, encoding = decode_header(msg.get("From"))[0]
if isinstance(fro, bytes):
fro = fro.decode(encoding)
if s == 0:
time.sleep(180)
mai_load(1)
print("From:", fro)
send_mail(fro)
mail.store(response[1], '+FLAGS', '\\Deleted')
print("=" * 100)
Solution:
had to change one line:
mail.store(response[1], '+FLAGS', '\\Deleted')
to
mail.store(str(i), '+FLAGS', '\\Deleted')

Create a Generator to read email and process messages

I am trying to write some code to read my inbox and process some attachments if present. I decided this would be a good time to learn how generators work as I want to process all messages that have a particular subject. I have gotten to the point where I can get all the attachments and relevant subjects but I sort of had to fake it as the iterator in the for i in range . . . was not advancing so I am advancing the latest_email_id in the loop
def read_email_from_gmail():
try:
print 'got here'
mail = imaplib.IMAP4_SSL(SMTP_SERVER)
mail.login(FROM_EMAIL,FROM_PWD)
mail.select('inbox')
type, data = mail.search(None, 'ALL')
mail_ids = data[0]
id_list = mail_ids.split()
first_email_id = int(id_list[0])
latest_email_id = int(id_list[-1])
print latest_email_id
while True:
for i in range(latest_email_id,first_email_id - 1, -1):
latest_email_id -= 1
#do stuff to get attachment and subject
yield attachment_data, subject
except Exception, e:
print str(e)
for attachment, subject in read_email_from_gmail():
x = process_attachment(attachment)
y = process_subject(subject)
Is there a more pythonic way to advance through my in-box using a generator to hold state in the in-box?
I have learned a bit more about generators and played around with the code I started with so I have a function that uses a generator to send each relevant email message subject to the main function. This is what I have so far, and it works great for my needs
import imaplib
import email
FROM_EMAIL = 'myemail#gmail.com'
FROM_PWD = "mygmail_password"
SMTP_SERVER = "imap.gmail.com"
SMTP_PORT = 993
STOP_MESSAGES = set(['Could not connect to mailbox',
'No Messages or None Retrieved Successfully',
'Could not retrieve some message',
'Finished processing'])
def read_emails():
mail = imaplib.IMAP4_SSL(SMTP_SERVER)
mail.login(FROM_EMAIL,FROM_PWD)
mail.select('inbox')
con_status, data = mail.uid('search', None, "ALL")
if con_status != 'OK':
yield 'Could not connect to mailbox'
try:
mail_ids = data[0].split()
except Exception:
yield 'No Messages or None Retrieved Successfully'
print mail_ids
processed = []
while True:
for mail_id in mail_ids:
status, mdata = mail.uid('fetch', mail_id, '(RFC822)')
if status != 'OK':
yield 'Could not retrieve some message'
if mail_id in processed:
yield 'Finished processing'
raw_msg = mdata[0][1]
structured_msg = email.message_from_string(raw_msg)
msg_subject = structured_msg['subject']
processed.append(mail_id)
yield msg_subject
To access my messages one by one, I then use the following block to get my messages
for msg_subj in read_emails():
if msg_subj not in STOP_MESSAGES:
do some stuff here with msg_subj
else:
print msg_subj
break
I am accessing these messages by their uid as I will be deleting them later and would like to use the uid as the key to manage deletion. For me the trick was to collect the uid in the list named processed and then check to see if I was going to circle through them again because I was working with a uid that had already been processed.

Categories

Resources