Receive mail from ERP software, change subject and forward - python

im complete new to this so sorry if this is a stupid question.
Im already searching the whole day for a solution of our problem.
Our Problem: We create an order for our supplier using our ERP software. The supplier want a specific subject in this email to get the mail picked up by there order receive system. We can't set the subject in out ERP software.
Workaround: ERP is sending the mail to an internal address and then we need to change the subject and forward it to the supplier.
We want to do this automatically. is this possible?
I saw a few thing about Python to do this, but not the complete solution. So i know its maybe very nooby, but who can and want to help me.
We are using Novell mail server. (that's also complete new for me :-( )
Update: i've created some code, but its not the best. :)
import smtplib, imaplib, email, re
#mail read, change and forward
imap_host = "SERVERNAME"
client = imaplib.IMAP4('SERVERNAME')
client.login('USERNAME', 'PWD')
client.select('INBOX') #, readonly=True
msgid = 1
status, data = client.fetch(msgid, "(RFC822)")
email_data = data[0][1]
client.close()
client.logout()
message = email.message_from_string(email_data)
message.replace_header("Subject", "test")
message.replace_header("From", 'test#test.com')
message.replace_header("To", 'EXTERN EMAILADRES')
smtp = smtplib.SMTP('SMTP SERVER')
smtp.starttls()
smtp.login('USERNAME', 'PWD')
from_addr = "AFZENDADRES"
to_addr = "EXTERN EMAILADRES"
smtp.sendmail(from_addr, to_addr, message.as_string())
#move mail to folder
client = imaplib.IMAP4('SERVERNAME')
client.login('USERNAME', 'PWD')
client.select('INBOX', readonly=False)
pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')
def parse_uid(data):
match = pattern_uid.match(data)
return match.group('uid')
resp, items = client.search(None, 'All')
email_ids = items[0].split()
latest_email_id = email_ids[0]
resp, data = client.fetch(latest_email_id, "(UID)")
msg_uid = parse_uid(data[0])
result = client.uid('COPY', msg_uid, 'INBOX/Afgehandeld')
if result[0] == 'OK':
mov, data = client.uid('STORE', msg_uid , '+FLAGS', '(\Deleted)')
client.expunge()
client.close()
client.logout()
Should be fine if this code can be updates so that it checks if there are mails from a sender or with some words in the subject. if there aren't then stop the script. If there are 1 or more mails then we need to change the subject and forward the email to our supplier. Who can help me to get this code better.

Related

How to fetch only the latest email using Gmail API in Python

How would I ago about coding a Python script to work whenever there is a new email in my inbox. Is there any special tools in the Gmail Python SDK that would make this easy to do instead of using MAPI and going the long rout of keep checking daily for new inbox updates?
You can use something like this.
def get_email():
#credentials
username ="youremail#gmail.com"
#generated app password
app_password= "emailPasswd"
# https://www.systoolsgroup.com/imap/
gmail_host= 'imap.gmail.com'
#set connection
mail = imaplib.IMAP4_SSL(gmail_host)
#login
mail.login(username, app_password)
#select inbox
mail.select("INBOX")
time.sleep(1)
#select specific mails
_, selected_mails = mail.search(None,"UNSEEN", '(FROM "specificUser#gmail.com")') # get emails only from specific sender
#total number of mails from specific user
for num in selected_mails[0].split():
your_function() # call your function here so for every new mail this will run
_, data = mail.fetch(num , '(RFC822)')
_, bytes_data = data[0]
#access data
subject_of_mail = email_message["subject"]
for part in email_message.walk():
if part.get_content_type()=="text/plain" or part.get_content_type()=="text/html":
message = part.get_payload(decode=True)
else:
pass
schedule.every(5).seconds.do(get_email)
#other schedule options
"""
schedule.every(10).minutes.do(get_email)
schedule.every().hour.do(get_email)
schedule.every().day.at("10:30").do(get_email)
schedule.every(5).to(10).minutes.do(get_email)
schedule.every().monday.do(get_email)
schedule.every().wednesday.at("13:15").do(get_email)
schedule.every().minute.at(":17").do(get_email)
"""
while True:
schedule.run_pending()
time.sleep(1)

What is a better way to edit email subjects

I have this issue where I need to periodically check a Gmail account and add subjects to emails with no subject. My current method is very hacky and I am hoping someone with more IMAP/Google API knowledge could suggest a better method.
Right now, my python script will check Gmail for messages and for emails with no subject, it will create a copy of the message and resend it (back to itself). Here is the code for that (authentication excluded:
# Select the inbox
mail.select()
# Get the UID of each email in the inbox with ""
subject typ, data = mail.uid('search', None, '(HEADER Subject "")')
# Loop for each of the emails with no subjects
for email_id in data[0].split():
print email_id
# Use the uid and get the email message
result, message = mail.uid('fetch', email_id, '(RFC822)')
raw_email = message[0][1]
email_msg = email.message_from_string(raw_email)
# Check that the subject is blank
if email_msg['Subject'] == '':
print email_msg['From']
print email_msg['To']
# Get the email payload
if email_msg.is_multipart():
payload = str(email_msg.get_payload()[0])
# Trim superfluous text from payload
payload = '\n'.join(payload.split('\n')[3:])
print payload
else:
payload = email_msg.get_payload()
# Create the new email message
msg = MIMEMultipart()
msg['From'] = email_msg['From']
msg['To'] = email_msg['To']
msg['Subject'] = 'No Subject Specified'
msg.attach(MIMEText(payload))
s = smtplib.SMTP('smtp.brandeis.edu')
print 'Sending Mail...'
print msg['To']
s.sendmail(email_msg['From'], [email_msg['To']], msg.as_string())
s.quit()
mail.close()
mail.logout()
I am hoping that there is a better way to do this with python's IMAP library or Google APIs that wouldn't involved resending the message.
There is no better way. Messages in IMAP are immutable — clients may cache them indefinitely. And some messages are signed too, quite a few these days, and your change likely breaks the signatures.

Wrong "uid" when searching with imaplib

I am experiencing a strange problem while developing my python application.
The application is supposed to parse a mail inbox for the unread messages, get a specific ones, process the body and store it into a database.
Everything seem to be working fine for my first 7 mails from my domain, but with the last one and the 4 #gmails, the results don't match with the expected, the mails stored into the database aren't the correct ones, in fact, they are exactly the 4th mail after the correct one.
I am showing the code that I developed, don't be too hard with me, I am kinda new coding:
main.py
from src_pckg import reader
reader.read("***#m***p.com", "***", "imap.***.com", 993, "noreply#s***d.com")
reader.py
def read(username, password, host, port, sender_of_interest):
#Con details
imap_con = imaplib.IMAP4_SSL(host, port)
imap_con.login(username, password)
imap_con.select("INBOX")
#Print all unread messages from a certain sender
status, response = imap_con.search(None, 'UNSEEN', '(FROM "%s")' % (sender_of_interest))
unread_msg_nums = response[0].split()
print(len(unread_msg_nums))
for e_id in unread_msg_nums:
status, data = imap_con.uid('fetch', e_id, '(RFC822)')
msg = data[0][1].decode(encoding='UTF-8')
if re.search("has given you a gift subscription", msg):
#Process the mail
return True

IMAP get sender name and body text?

I am using this code:
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(myusername, mypassword)
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
result, data = mail.fetch(latest_email_id, "(RFC822)") # fetch the email body (RFC822) for the given ID
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
print raw_email
and it works, except, when I print raw_email it returns a bunch of extra information, how can I, parse, per say, the extra information and get just the From and body text?
Python's email package is probably a good place to start.
import email
msg = email.message_from_string(raw_email)
print msg['From']
print msg.get_payload(decode=True)
That should do ask you ask, though when an email has multiple parts (attachments, text and HTML versions of the body, etc.) things are a bit more complicated.
In that case, msg.is_multipart() will return True and msg.get_payload() will return a list instead of a string. There's a lot more information in the email.message documentation.
Alternately, rather than parsing the raw RFC822-formatted message - which could be very large, if the email contains attachments - you could just ask the IMAP server for the information you want. Changing your mail.fetch line to:
mail.fetch(latest_email_id, "(BODY[HEADER.FIELDS (FROM)])")
Would just request (and return) the From line of the email from the server. Likewise setting the second parameter to "(UID BODY[TEXT])" would return the body of the email. RFC2060 has a list of parameters that should be valid here.
IMAP high level lib: https://github.com/ikvk/imap_tools (I am author)
from imap_tools import MailBox, A
with MailBox('imap.mail.com').login('test#mail.com', 'password', 'INBOX') as mailbox:
for msg in mailbox.fetch(A(all=True)):
sender = msg.from_
body = msg.text or msg.html
Alternatively, you can use Red Box (I'm the author):
from redbox import EmailBox
# Create email box instance
box = EmailBox(
host="imap.example.com",
port=993,
username="me#example.com",
password="<PASSWORD>"
)
# Select an email folder
inbox = box["INBOX"]
# Search and process messages
for msg in inbox.search(all=True):
# Process the message
print(msg.from_)
print(msg.to)
print(msg.subject)
print(msg.text_body)
print(msg.html_body)
Some relevant links in the documentations:
More about querying
More about manipulating the message
More about configuring the email box
To install:
pip install redbox
Links:
Source code
Documentation

Python - imaplib - View message to specific sender

I have a python script that is checking emails on Gmail's IMAP server, it displays the latest email on the server. The email address however is receiving emails from multiple different accounts. What would I do to take this script and have it view ONLY messages that are to a specific sender? For example, any email only sent to "johndoe#gmail.com" will come up.
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('myemail#gmail.com', 'password123')
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
result, data = mail.fetch(latest_email_id, "(RFC822)") # fetch the email body (RFC822) for the given ID
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
Thanks in advance! :)
change:
result, data = mail.search(None, "ALL")
to:
result, data = mail.search(None, '(TO "johndoe#gmail.com")')

Categories