I want to make postfix send all emails to a python script that will scan the emails.
However, how do I pipe the output from postfix to python ?
What is the stdin for Python ?
Can you give a code example ?
Rather than calling sys.stdin.readlines() then looping and passing the lines to email.FeedParser.FeedParser().feed() as suggested by Michael, you should instead pass the file object directly to the email parser.
The standard library provides a conveinience function, email.message_from_file(fp), for this purpose. Thus your code becomes much simpler:
import email
msg = email.message_from_file(sys.stdin)
To push mail from postfix to a python script, add a line like this to your postfix alias file:
# send to emailname#example.com
emailname: "|/path/to/script.py"
The python email.FeedParser module can construct an object representing a MIME email message from stdin, by doing something like this:
# Read from STDIN into array of lines.
email_input = sys.stdin.readlines()
# email.FeedParser.feed() expects to receive lines one at a time
# msg holds the complete email Message object
parser = email.FeedParser.FeedParser()
msg = None
for msg_line in email_input:
parser.feed(msg_line)
msg = parser.close()
From here, you need to iterate over the MIME parts of msg and act on them accordingly. Refer to the documentation on email.Message objects for the methods you'll need. For example email.Message.get("Header") returns the header value of Header.
Related
An email comes in with the following header from an #outlook.com address
Message-ID:
<DM5PR1101MB2074A897F300D11D32C71B75EC049#DM5PR1101MB2074.namprd11.prod.outlook.com>
To respond with Python I put that message identifier in the In-Reply-To header
from email.message import EmailMessage
msg = EmailMessage()
msg['In-Reply-To'] = '<DM5PR1101MB2074A897F300D11D32C71B75EC049#DM5PR1101MB2074.namprd11.prod.outlook.com>'
However, when I print this message the header appears as follows:
In-Reply-To: =?utf-8?q?=3CDM5PR1101MB2074A897F300D11D32C71B75EC049=40DM5PR11?=
=?utf-8?q?01MB2074=2Enamprd11=2Eprod=2Eoutlook=2Ecom=3E?=
And when it arrives in Outlook it's not put in the same conversation thread as the original message.
Does anyone know why this may be happening and/or know of any work-around?
I suspect that this is happening because Python is trying to split the header across multiple lines since this header is above the RFC-specified line length and when it splits across multiple lines it starts each line with '?utf-8?q and converts the < character to ?=3C, etc... Whereas Outlook is expecting the header to be of the format
In-Reply-To':
<DM5PR1101MB2074A897F300D11D32C71B75EC049#DM5PR1101MB2074.namprd11.prod.outlook.com>'
Perhaps if someone knows how to force the header to be in this format that would suffice as a work-around.
Any help would be greatly appreciated :)
I am working on sending emails with python and have a decent grasp on that however I am struggling with using info from a CSV File.
I have a piece of code:
s.login('example#gmail.com', 'expassword')
that when used with a preset login and password works, it sends the email to my recipient, which is later set in my code, however as soon as I use the code:(chooses a random email and password from a CSV to send from(for a spam email demo))
with open ('C:/Filepath/randomsender.csv') as file:
reader = csv.reader(file)
sender = random.choice(list(reader))
followed by
s.login(sender)
I get an auth error because it cannot read the chosen line properly even though the result of sender is formatted the same as:
'example#gmail.com', 'expassword'
If you want to pass list elements as position param, you need to unpack it.
this might help
e.g.
s.login(*sender)
I'm writing an email parser for python 2.7 that will be invoked via sendmail using an alias, parsed using the email module and then processed and stored into an oracle database:
From /etc/aliases:
myalias: | /my/python/script.py
I'm having trouble "slurping" all of stdin into a string object that I can use with the email module:
import email
# Slurp stdin and store into message
message =
msg = email.message_from_string(message)
# Do something with it
print msg['Subject']
What would be the most efficient way to do this? I've tried stdin.readlines() but it ends up as a list.
Thx for any help. (Sorry if this is noobish... I'm a perl convert and been forced to standardize my tools using python and this is only my second script. Well not really "forced", I've been wanting to do this for some time but not under the gun of a deadline like now)
sys.stdin.readlines() returns a list of lines. If what you want is one long (multi-line) string, use sys.stdin.read().
I need to generate a MIME attachment that contains a Base64 encoded file. However what I need to also allow for is encoding the attachment WITHOUT any new lines. The code I have is as followed:
msg_obj = MIMEMultipart()
msg_atch = MIMEBase(mime_type, mime_subtype)
msg_atch.set_payload(file_data)
Encoders.encode_base64(msg_atch)
msg_obj.attach(msg_atch)
What I have tried to perform to remove the new lines in the attach base64 message was this:
msg_obj = MIMEMultipart()
msg_atch = MIMEBase(mime_type, mime_subtype)
msg_atch.set_payload(file_data)
Encoders.encode_base64(msg_atch)
msg_atch.strip()
msg_obj.attach(msg_atch)
However this failed to change the results of the data. If anyone has any ideas on how to allow for this, it would be great.
I noticed in the penultimate line of your 2nd sample code, you call the msg_atch.strip() function. The problem with this is that there isn't any function strip() of MIMEBase.
What you probably want to do is something along the lines of this:
msg_obj = MIMEMultipart()
msg_atch = MIMEBase(mime_type, mime_subtype)
msg_atch.set_payload(file_data)
Encoders.encode_base64(msg_atch)
msg_atch._payload = msg_atch._payload.replace('\n','')
msg_obj.attach(msg_atch)
The MIMEBase._payload string is the actual (in this case, base64) content used by the attachment.
This code will take the inner content of the MIMEBase attachment and eliminate the extra newlines - including the ones inside to provide nice formatting of base64 text for "human readability" (my question is why they even bother). If you just want to get rid of the newlines at the end, just use msg_atch._payload = msg_atch._payload.rstrip('\n').
Keep in mind that the header of the attachment (Content-Type: application/octet-stream and MIME-Version: 1.0 are parts) require these newlines.
Also, try to remember that you shouldn't normally be editing internal variables in this fashion. However, one of the things I find nice about Python is that there are really no private members of a class, so you can modify whatever you want in a class. We can do whatever we want, especially if it's a special condition.
Happy Coding!
I just need to write a simple python CGI script to parse the contents of a POST request containing JSON. This is only test code so that I can test a client application until the actual server is ready (written by someone else).
I can read the cgi.FieldStorage() and dump the keys() but the request body containing the JSON is nowhere to be found.
I can also dump the os.environ() which provides lots of info except that I do not see a variable containing the request body.
Any input appreciated.
Chris
If you're using CGI, just read data from stdin:
import sys
data = sys.stdin.read()
notice that if you call cgi.FieldStorage() before in your code, you can't get the body data from stdin, because it just be read once.