1

I did some research here, I did see a similar question (Send formatted list of tuples as body of an email)

But my tuple is not a pair, my tuple is a SQL query result like:

mylist =[('Mike','Boston','32','doctor'),('kate','Boston','32','doctor')....]

Then I tried below format

body = "'%s,%s,%s,%s'"% (mylist[0],mylist[1],mylist[2],mylist[3])

But I receive an email with an empty body.

smtpObj.sendmail(sender, receivers, message)  

Anything wrong with my code? Thank you for your help.

My code in email part is :

import smtplib

sender = 'xxxxxxx@gmail.com'
receivers = ['xxxxxxxx@gmail.com']

i=0
while (i<len(mylist)):

    message ="'%s,%s,%s,%s'"% (mylist[0],mylist[1],mylist[2],mylist[3])
    i=i+1

smtpObj = smtplib.SMTP('**********')
smtpObj.sendmail(sender, receivers, message)
Todor Minakov
  • 19,097
  • 3
  • 55
  • 60
LearnPython
  • 15
  • 1
  • 6

3 Answers3

2

mylist is a two dimensional structure - a list of tuples; with your current loop, you will actually get the first four tuples in the list - not the 4 tuples members, as you would expect.

Presuming you want each tuple, on a separate line, this will get it for you:

body = ''
for line in mylist:
    body += "'%s,%s,%s,%s\n'"% (line[0],line[1],line[2],line[3])

Note each new line is appended (+=), and finishes with a newline chapter (\n).

That will get you the message content you might actually expect, but will most probably not resolve your issue "But I receive an email with an empty body.".
The reason for it is the lack of any headers in the message; according to RFC 5322 - the latest standard, there must be at least a From and Date headers. Some MTAs are quite forgiving and will accept the message without them, but those are minorities.

So the actual body initialization should be (instead of the empty string up there):

import datetime

date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" )
body = 'From: %s\r\nDate: %s\r\n\r\n'% (sender, date)
# the loop follows

Note the delimiter between the headers is \r\n - CRLF, and the headers are separated from the message body with a blank line.


By the way, the majority of the users go with the email.mime.text.MIMEText class and its surrounding package, precisely not to deal with this low-level operations.

Community
  • 1
  • 1
Todor Minakov
  • 19,097
  • 3
  • 55
  • 60
  • 2
    Thank you so much, you are right! I removed my headers when I did the test. After I added them back, I can receive the email with content! Thanks a ton! – LearnPython Feb 23 '18 at 05:17
1

Your data structure is, in a way, multidimensional. What this means is you'll have to access first, which tuple and then the tuple's elements.

Try:

body = "%s,%s,%s,%s" % (mylist[0][0],mylist[0][1],mylist[0][2],mylist[0][3])

This will prepare a body containing the items found in the first tuple. You can change which tuple you access by changing the first [0] to whatever is the tuple index within mylist.

Also, no need for the additional two '

esreli
  • 4,993
  • 2
  • 26
  • 40
  • Thank you for your help! Unfortunately, I still receive an empty email. I am wondering if put "body" as a parameter in smtpObj.sendmail() cause the issue? – LearnPython Feb 23 '18 at 04:36
0

If your code is as written, then I haven't tested it but as achi noted in their answer your list is multidimensional. In fact, you have an extra set of parenthesis surrounding the items that you retrieve from the list when you index, so not only are you retrieving tuples, but you then nest them right back into another tuple. Additionally:

  • You have an extra set of double quotes surrounding the format string.
  • You appear to be iterating over each tuple (query row) in the list but generating and overwriting the entire message on each pass.
  • You don't usually want or need an indexed loop in Python. Rather, try the for e in list: paradigm. Then, simply append each formatted tuple to your message as you traverse the list.

Putting it all together:

mylist =[('Mike','Boston','32','doctor'), ('kate','Boston','32','doctor'), ...]

for row in mylist:
    message += '%s, %s, %s, %s' % row
    ...

smtpObj = smtplib.SMTP(...)
smtpObj.sendmail(sender, receiver, message)

Note that in the above example, row is a tuple from mylist, so it is used directly when generating the string (ie not (row), but rather row). And just in case you're wondering, the string append operation should be reasonably efficient on most systems.

AnOccasionalCashew
  • 601
  • 1
  • 5
  • 15