How to send message to multiple recipients? - python

I'm having some trouble sending a message to multiple addresses using the Gmail API. I've successfully sent a message to only one address, but get the following error when I include multiple comma-separated addresses in the 'To' field:
An error occurred: <HttpError 400 when requesting
https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json
returned "Invalid to header">
I'm using the CreateMessage and SendMessage methods from this Gmail API guide:
https://developers.google.com/gmail/api/guides/sending
That guide states that the Gmail API requires messages that are RFC-2822 compliant. I again didn't have much luck using some of these addressing examples in the RFC-2822 guide:
https://www.rfc-editor.org/rfc/rfc2822#appendix-A
I'm under the impression that 'mary#x.test, jdoe#example.org, one#y.test' should be a valid string to pass into the 'to' parameter of CreateMessage, but the error that I received from SendMessage leads me to believe otherwise.
Please let me know if you can recreate this problem, or if you have any advice on where I may be making a mistake. Thank you!
Edit: Here is the actual code that yields an error...
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string())}
def SendMessage(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message)
.execute())
print 'Message Id: %s' % message['id']
return message
except errors.HttpError, error:
print 'An error occurred: %s' % error
def ComposeEmail():
# build gmail_service object using oauth credentials...
to_addr = 'Mary Smith <mary#x.test>, jdoe#example.org, Who? <60one#y.test>'
from_addr = 'me#address.com'
message = CreateMessage(from_addr,to_addr,'subject text','message body')
message = SendMessage(gmail_service,'me',message)

Getting "Invalid to header" when sending with multiple recipients (comma delimited) in a single header was a regression that was fixed on 2014-08-25.

As James says in its comment, you shouldn't waste time trying to use Gmail API when Python has excellent documented support for using SMTP : email module can compose message including attachements, and smtplib sends them. IMHO you could use Gmail API for what works out of the box but should use the robust modules form Python Standard Library when things go wrong.
It looks like you want to send a text only message : here is a solution adapted from the email module documentation and How to send email in Python via SMTPLIB from Mkyong.com:
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText
msg = MIMEText('message body')
msg['Subject'] = 'subject text'
msg['From'] = 'me#address.com'
msg['To'] = 'Mary Smith <mary#x.test>, jdoe#example.org, "Who?" <60one#y.test>'
# Send the message via Gmail SMTP server.
gmail_user = 'youruser#gmail.com'
gmail_pwd = 'yourpassword'smtpserver = smtplib.SMTP("smtp.gmail.com",587)
smtpserver = smtplib.SMTP('smtp.gmail.com')smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
smtpserver.login(gmail_user, gmail_pwd)
smtpserver.send_message(msg)
smtpserver.quit()

See also User.drafts reference - error"Invalid to header"
Apparently this bug was recently introduced in Gmail API.

Related

django_cron not sending email

I have just installed django_cron not django_crontab though, somehow I am trying to send an email as notification but it just wouldn't work.
this is just for testing purpose so I set it to 1 minute.
the code was a bit more complex before but it didn't work so I used the most simplified way to send email in order to make sure that it's not working. Also even used it as a post method to test, and it tested out working perfectly if a post method called the follow codes
class MyCronJob(CronJobBase):
RUN_EVERY_MINS = 1 # every minute
schedule = Schedule(run_every_mins=RUN_EVERY_MINS)
code = 'Email_Test' # a unique code
def do(self):
print('######################################')
send_mail(
'Subject here from cron',
'Here is the message.',
'from#email.com',
['to#emailcom'],
fail_silently=False,
)
I tried running python manage.py runcrons and python manage.py runcrons --force and waited, (no errors, I also added the print because I want to see if the code even runs and good, I see the ################# got printed)
can someone please give me an advise?
Thanks in advance
Try a custom function for sending mail. I tried send_mail function and it did not work for me and i did not find any bug or explanation on this topic. Below is an example of sending html emails using smtplib.
import smtplib
def send_email(email, subject, message):
text = subject
html = message
msg = MIMEMultipart('alternative')
html_part = MIMEText(html, 'html')
text_part = MIMEText(text, 'plain')
msg.attach(text_part)
msg.attach(html_part)
msg['Subject'] = subject
msg['From'] = SENDER_EMAIL
msg['To'] = email
s = smtplib.SMTP(settings.GMAIL_SMTP)
s.ehlo()
s.starttls()
s.login(SENDER_EMAIL, SENDER_PASSWORD)
s.sendmail(SENDER_EMAIL, email, msg.as_string())
s.quit()
please make sure first you must have to import library from django.core.mail, to using send_mail. I know it's too late to help, but u can try this..
from django_cron import CronJobBase, Schedule
from django.core.mail import send_mail
class my_scheduled_job(CronJobBase):
RUN_EVERY_MINS = 1
schedule = Schedule(run_every_mins=RUN_EVERY_MINS)
code = 'user_dashboard.autoemail.my_scheduled_job'
def do(self):
subject= 'Send Email With Automatic Schedule'
message= 'Test send email :'
email_to= ['xxxxxxxx#gmail.com']
email_user(subject_test, message_test, email_to_test)
print ("done")
def email_user(subject, message, email_to):
email_from = 'noreply#xxxx.id'
send = send_mail(subject, message, email_from, email_to)
return send

Adding Content-Disposition header in Python - email isn't sent

Following the directions in Python's email examples and in several Stack Overflow questions, I wrote the following function (sending through the Gmail SMTP server):
def send_email(emailaddr, message, attachmentfile = None, subject = None):
try:
smtpconn = smtplib.SMTP(mainconf["SMTPHOST"], mainconf["SMTPPORT"])
smtpconn.set_debuglevel(1)
smtpconn.ehlo()
smtpconn.starttls()
smtpconn.login(mainconf["SMTPUSER"], mainconf["SMTPPASS"])
if not attachmentfile:
message = '\n' + message
smtpconn.sendmail(mainconf["EMAILFROM"], emailaddr, message)
else:
multipart = MIMEMultipart()
multipart['Subject'] = subject if subject else "Attachment"
multipart['From'] = mainconf["EMAILFROM"]
multipart['To'] = emailaddr
with open(attachmentfile, 'rb') as fp:
filepart = MIMEApplication(fp.read())
multipart.attach(filepart)
multipart.attach(message)
smtpconn.sendmail(mainconf["EMAILFROM"], emailaddr, multipart.as_string())
generallog.info("Sent an email to {0}".format(emailaddr))
except:
generallog.warn("Email sending to {0} failed with error message {1}".format(emailaddr, traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])))
This works fine for sending an email with an attachment, but it results in the famous noname problem (that's just one of several SO questions on the subject). So I add in this:
filepart.add_header('Content-Disposition','attachment',filename=os.basename(attachmentfile))
Then Gmail simply refuses to send the email. When I run this code in the Python shell, I get the standard message accepted message, but the message is never delivered.
Why might this be happening?

Send email with double angle brackets (open-close) in content by Python Gmail-API

I want to send an email by the Gmail-API in Python, but I constantly received the following error:
<HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Invalid value for .....">
I tried to change everything and concluded that the error happens when I include an double open close angle bracket ('<<' and '>>') (see example) in the email. I tried everything to parse the text to something else, but i'm thinking that the problem lies in the fact that i use 'raw'... But 'raw' is the only way the example of Google shows.
Is there an other way to send an email by the gmail-api? or, in other words, what can I do to be able to send an email with angle brackets in the text?
Thanks!
My current code is below (example code from Google):
import base64
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
import os
from apiclient import errors
(...other code...)
SendMessage(service, "me", CreateMessage("me", sender, "<<NOT OK>> " + action, "TEST!"))
(...other code...)
def SendMessage(service, user_id, message):
"""Send an email message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
message: Message to be sent.
Returns:
Sent Message.
"""
try:
# print message
message = service.users().messages().send(userId=user_id, body=message).execute()
print '<mail> Message SEND (Id: %s' % message['id'] + ')'
return message
except errors.HttpError, error:
print 'An error occurred (SendMessage): %s' % error
def CreateMessage(sender, to, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64 encoded email object.
"""
print "<mail> send to: " + to
print "<mail> subject: " + subject
print "<mail> message: " + message_text
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.b64encode(message.as_string())}
You need to use:
base64.urlsafe_b64encode(message.as_string())
with the url-safe base64 alphabet, otherwise you'll have invalid characters in your 'raw' field. See:
https://developers.google.com/gmail/api/v1/reference/users/messages/send

Can I get the incoming message by using Mailgun?

A use Mailgun to send b a email, after b receive the email and reply to a.If I want to track the email coming from b, How I can get the email?
Here is the code:
1.sendmail.py
from smtplib import SMTP
import requests
login_name = "postmaster#zzb.mailgun.org"
password = "********"
def send_message_via_smtp():
smtp = SMTP("smtp.mailgun.org", 587)
smtp.login(login_name, password)
smtp.sendmail("zebozhuang#163.com","348284770#qq.com", "Subject:mailgun test \n\n just for test.\n\n")
smtp.quit()
if __name__=="__main__":
send_message_via_smtp()
2.create_route.py
import requests
from werkzeug.datastructures import MultiDict
def create_route():
return requests.post(
"https://api.mailgun.net/v2/routes",
auth=("api", "key-9c4-t2q6fouilngjummvtv1rge7t00f2"),
data=MultiDict([("priority", 1),
("description", "Sample route"),
("expression", "match_recipient('.*#qq.com')"),
("action", "forward('qiyazhuang#gmail.com')"),
("action", "stop()")])
)
I create the route and I run the script sendmail.py.After someone who use email 348284770#qq.com reply to the other who use email zebozhuang#163.com, the Gmail
can not receive the message by using the Mailgun method 'forward'.
Could anyone tell me why?
Your messages are likely being delivered. Check the "Logs" tab of the Mailgun Control Panel.
Do you see any entries that look like this:
Routed: .*#qq.com -> qiyazhuang#gmail.com 'SUBJECT HERE'
The "Routed" prefix means that the message triggered a Route. If you're seeing this, and the next log entry is prefixed with "Delivered", the message is likely being delivered to Gmail without issue. Check your Gmail spam folder if you still don't see the messages in the inbox folder.
Disclaimer: I work for Mailgun Support. :)

How to receive mail using python

I would like to receive email using python. So far I have been able to get the subject but not the body. Here is the code I have been using:
import poplib
from email import parser
pop_conn = poplib.POP3_SSL('pop.gmail.com')
pop_conn.user('myusername')
pop_conn.pass_('mypassword')
#Get messages from server:
messages = [pop_conn.retr(i) for i in range(1, len(pop_conn.list()[1]) + 1)]
# Concat message pieces:
messages = ["\n".join(mssg[1]) for mssg in messages]
#Parse message intom an email object:
messages = [parser.Parser().parsestr(mssg) for mssg in messages]
for message in messages:
print message['subject']
print message['body']
pop_conn.quit()
My issue is that when I run this code it properly returns the Subject but not the body. So if I send an email with the subject "Tester" and the body "This is a test message" it looks like this in IDLE.
>>>>Tester >>>>None
So it appears to be accurately assessing the subject but not the body, I think it is in the parsing method right? The issue is that I don't know enough about these libraries to figure out how to change it so that it returns both a subject and a body.
The object message does not have a body, you will need to parse the multiple parts, like this:
for part in message.walk():
if part.get_content_type():
body = part.get_payload(decode=True)
The walk() function iterates depth-first through the parts of the email, and you are looking for the parts that have a content-type. The content types can be either text/plain or text/html, and sometimes one e-mail can contain both (if the message content_type is set to multipart/alternative).
The email parser returns an email.message.Message object, which does not contain a body key, as you'll see if you run
print message.keys()
What you want is the get_payload() method:
for message in messages:
print message['subject']
print message.get_payload()
pop_conn.quit()
But this gets complicated when it comes to multi-part messages; get_payload() returns a list of parts, each of which is a Message object. You can get a particular part of the multipart message by using get_payload(i), which returns the ith part, raises an IndexError if i is out of range, or raises a TypeError if the message is not multipart.
As Gustavo Costa De Oliveir points out, you can use the walk() method to get the parts in order -- it does a depth-first traversal of the parts and subparts of the message.
There's more about the email.parser module at http://docs.python.org/library/email.message.html#email.message.Message.
it also good return data in correct encoding in message contains some multilingual content
charset = part.get_content_charset()
content = part.get_payload(decode=True)
content = content.decode(charset).encode('utf-8')
Here is how I solved the problem using python 3 new capabilities:
import imaplib
import email
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(username, password)
mail.select(readonly=True) # refresh inbox
status, message_ids = mail.search(None, 'ALL') # get all emails
for message_id in message_ids[0].split(): # returns all message ids
# for every id get the actual email
status, message_data = mail.fetch(message_id, '(RFC822)')
actual_message = email.message_from_bytes(message_data[0][1])
# extract the needed fields
email_date = actual_message["Date"]
subject = actual_message["Subject"]
message_body = get_message_body(actual_message)
Now get_message_body is actually pretty tricky due to MIME format. I used the function suggested in this answer.
This particular example works with Gmail, but IMAP is a standard protocol, so it should work for other email providers as well, possibly with minor changes.
if u want to use IMAP4. Use outlook python library, download here : https://github.com/awangga/outlook
to retrieve unread email from your inbox :
import outlook
mail = outlook.Outlook()
mail.login('emailaccount#live.com','yourpassword')
mail.inbox()
print mail.unread()
to retrive email element :
print mail.mailbody()
print mail.mailsubject()
print mail.mailfrom()
print mail.mailto()

Categories