Python Mail with Mandrill To Multiple email id - python

Email With Mandrill to multiple emailId but it only deliver to id which is first in the list to rest it does not send.I want to send mail to multiple users using mandrill API
here is my code :
class mandrillClass:
def mandrillMail(self,param):
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
msg = MIMEMultipart('alternative')
msg['Subject'] = param['subject']
msg['From'] = param['from']
msg['To'] = param['to']
html = param['message']
print html
text = 'dsdsdsdds'
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
username = 'xyz#gmail.com'
password = 'uiyhiuyuiyhihuohohio'
msg.attach(part1)
msg.attach(part2)
s = smtplib.SMTP('smtp.mandrillapp.com', 587)
s.login(username, password)
s.sendmail(msg['From'], msg['To'], msg.as_string())
s.quit()
and here i am calling the function
from API_Program import mandrillClass
msgDic = {}
msgDic['subject'] = "testing"
msgDic['from'] = "xyz#gmail.com"
#msgDic['to'] = 'abc#gmail.com','example#gmail.com'
COMMASPACE = ', '
family = ['abc#gmail.com','example#gmail.com']
msgDic['to'] = COMMASPACE.join(family)
msgDic['message'] = "<div>soddjags</div>"
mailObj = mandrillClass()
mailObj.mandrillMail(msgDic)

Since you're using smtplib, you'll want to review the documentation for that SMTP library on how you specify multiple recipients. SMTP libraries vary in how they handle multiple recipients. Looks like this StackOverflow post has information about passing multiple recipients with smtplib: How to send email to multiple recipients using python smtplib?
You need a list instead of just strings, so something like this:
msgDic['to'] = ['abc#gmail.com','example#gmail.com']
So, your family variable is declared properly, and you shouldn't need to do anything to that.

Try:
msgDic['to'] = [{"email":fam} for fam in family]
From the docs it looks like they expect this structure:
msgDic['to'] = [ {"email":"a#b.c", "name":"a.b", "type":"to"},
{"email":"x#y.z", "name":"x.z", "type":"cc"}
]
where you can omit name and type.

Related

How to replace body text in MIME message?

I am trying to send an automated email to various users with the lake that they are subscribed to changing:
message = MIMEMultipart()
message['From'] = email # Sender
message['Subject'] = "Algae Bloom Alert\n" # Subject
for user in subscriber_dict:
sms_gateway = subscriber_dict[user]['email']
message['To'] = subscriber_dict[user]['email']
body = (
f"This is an algae alert for Lake {subscriber_dict[user]['lake']}.\n\n"
f"Sent at {sent_time_date} {sent_time_time}"
)
message.attach(MIMEText(body, 'plain')) # Attaching body to email
sms = message.as_string()
server.sendmail(email, sms_gateway, sms)
# Reset body here ideally
print(f"Email sent at {formatted_time}")
However, when the emails are sent, each successive email contains the contents from the emails prior to it. Does anyone know how I can reset the body so that I am not attaching to the previous bodies but rather writing new ones?
Don't reuse the same message. Create a new one inside the loop.
Your code seems to be written for Python 3.5 or earlier. The email library was overhauled in 3.6 and is now quite a bit more versatile and logical. Probably throw away what you have and start over with the examples from the email documentation.
from email.message import EmailMessage
...
for user in subscriber_dict:
message = EmailMessage()
message['From'] = email
message['Subject'] = "Algae Bloom Alert" # no \n
message['To'] = subscriber_dict[user]['email']
message.set_content(
f"This is an algae alert for Lake {subscriber_dict[user]['lake']}.\n\n"
f"Sent at {sent_time_date} {sent_time_time}"
)
server.send_message(message)
print(f"Email sent at {formatted_time}")
You might want to avoid calling your sender variable email to avoid shadowing the email library, although in this example it doesn't really matter.
With .set_content() you could actually reuse the same message over and over but there is no actual benefit from that, and the problems if you fail to replace some part of an earlier message by mistake could be ugly. (For example, a typo could cause you to send the same message to the same recipient as many times as you have users!)
Righto - there's no need to keep digging back into subscriber_dict. Instead of:
for user in subscriber_dict:
sms_gateway = subscriber_dict[user]['email']
You can do:
for user in subscriber_dict.values():
sms_gateway = user['email']
Your for loop is reusing the same message. It should probably create a new one on each loop:
FROM_ADDR = "jake#lakefacts.gov.au"
for user in subscriber_dict.values():
message = MIMEMultipart()
message['From'] = FROM_ADDR
message['To'] = user['email']
message['Subject'] = "Algae Bloom Alert\n"
body = (
f"This is an algae alert for Lake {user['lake']}.\n\n"
f"Sent at {sent_time_date} {sent_time_time}"
)
message.attach(MIMEText(body, 'plain'))
sms_gateway = user['email']
sms = message.as_string()
server.sendmail(email, sms_gateway, sms)
print(f"Email sent at {formatted_time}")

using python smtp,only one receipent is getting mail

i am new to python,and below is the code which is suppose to send mail to multiple receipent but only dipeshyog94#gmail.com is getting a mail. milanthapa898#gmail.com which is second on To and alexlee94#gmail.com which is on cc is no getting the mail
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import smtplib
owner_emp_id_email = "dipeshyogi94#gmail.com,milanthapa989#gmail.com"
mymail='milanthapa898#gmail.com'
msg = MIMEMultipart()
msg['From'] = mymail
msg['To'] = owner_emp_id_email
cc_mail = "alexlee94#gmail.com"
msg['Cc'] = cc_mail
print('####44444444444444########\n')
print(owner_emp_id_email)
msg['Subject'] = 'Automated Test Mail with python'
a = 'Milan Thapa'
#body = 'Dear '+spoc_name+',\n\nYou have created new job with below Details:\n\nProject ID : '+project_ID+'\n\nProject Name : '+ibu_name+'\n\nJob Description : ' +job_description +'\n\nThanks and Regards,\n\nMilan Thapa'
html = """\
<html>
<head></head>
<body>
<p>'Dear <b>{}<b>
</p>
</body>
</html>
""".format(a)
msg.attach(MIMEText(html,'html'))
text = msg.as_string()
try:
server = smtplib.SMTP('smtp.gmail.com:587')
except:
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.ehlo()
server.login(mymail,'password')
server.sendmail(mymail,owner_emp_id_email,text)
server.quit()
i am stuck in this couldn't send the mail to multiple users.
any help will be greatly appreciated!
thanks in advance
The information in the headers doesn't control where the message actually goes. The second argument to sendmail is the only place where this is controlled. This value should be a list, not a comma-separated string.
owner_emp_id_email = "dipeshyogi94#gmail.com,milanthapa989#gmail.com"
env_rcpts = owner_emp_id_email.split(",")
# ...
cc_mail = "alexlee94#gmail.com"
env_rcpts.append(cc_mail)
# ...
server.sendmail(mymail,env_rcpts,text)
You'll notice that you could also add addresses which are neither in To: or Cc: (or a number of other headers which serve the same purpose) to effectively implement Bcc:
Maybe also look at send_message which saves you from having to separately convert your message to a string you can pass to sendmail.
msg['To'] = owner_emp_id_email
Here owner_emp_id_email is a string.
Make it a list of email ids. Then it would work.
to_ids = owner_emp_id_email.split(',')
msg['To'] = to_ids
>>> help(smtplib)
to_addrs: A list of addresses to send this mail to. A bare string will be treated as a list with 1 address.
You need to convert your CSV string to a list like mentioned in the the other answer. With this answer I just wanted to demonstrate how can we use the python's amazing help function when stuck.

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

Python3 multipartmime email (text, email, and attachment)

I'm creating some emails in Python and I'd like to have HTML, text, and an attachment. My code is 'working', though its outputs are shown by Outlook as EITHER HTML or text, while showing the other 'part' (email or txt) as an attachment. I'd like to have the robust-ness of both email and text versions along with the file attachment.
Is there a fundamental limitation or am I making a mistake?
#!/usr/bin/env python3
import smtplib,email,email.encoders,email.mime.text,email.mime.base
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "me#me.com"
you = "you#you.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('mixed')
msg['Subject'] = "msg"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi\nThis is text-only"
html = """\
<html> This is email</html>
"""
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
#attach an excel file:
fp = open('excelfile.xlsx', 'rb')
file1=email.mime.base.MIMEBase('application','vnd.ms-excel')
file1.set_payload(fp.read())
fp.close()
email.encoders.encode_base64(file1)
file1.add_header('Content-Disposition','attachment;filename=anExcelFile.xlsx')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part2)
msg.attach(part1)
msg.attach(file1)
composed = msg.as_string()
fp = open('msgtest.eml', 'w')
fp.write(composed)
fp.close()
I found this has in fact been answered. Strange how the search feature is less effective than the 'related' boxes.
Sending Multipart html emails which contain embedded images

PGP-signing multipart e-mails with Python

I'm currently trying to add PGP signing support to my small e-mail sending script (which uses Python 3.x and python-gnupg module).
The code that signs message is:
gpg = gnupg.GPG()
basetext = basemsg.as_string().replace('\n', '\r\n')
signature = str(gpg.sign(basetext, detach=True))
if signature:
signmsg = messageFromSignature(signature)
msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha1",
protocol="application/pgp-signature")
msg.attach(basemsg)
msg.attach(signmsg)
else:
print('Warning: failed to sign the message!')
(Here basemsg is of email.message.Message type.)
And messageFromSignature function is:
def messageFromSignature(signature):
message = Message()
message['Content-Type'] = 'application/pgp-signature; name="signature.asc"'
message['Content-Description'] = 'OpenPGP digital signature'
message.set_payload(signature)
return message
Then I add all the needed headers to the message (msg) and send it.
This works well for non-multipart messages, but fails when basemsg is multipart (multipart/alternative or multipart/mixed).
Manually verifying the signature against the corresponding piece of text works, but Evolution and Mutt report that the signature is bad.
Can anybody please point me to my mistake?
The problem is that Python's email.generator module doesn't add a newline before the signature part. I've reported that upstream as http://bugs.python.org/issue14983.
(The bug was fixed in Python2.7 and 3.3+ in 2014)
What is actually the MIME structure of basemsg? It appears that it has too many nested parts in it. If you export a signed message from e.g. Evolution, you'll see that it has just two parts: the body and the signature.
Here's an example which generates a message on stdout that can be read and the signature verified on both mutt (mutt -f test.mbox) and Evolution (File -> Import).
import gnupg
from email.message import Message
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
body = """
This is the original message text.
:)
"""
gpg_passphrase = "xxxx"
basemsg = MIMEText(body)
def messageFromSignature(signature):
message = Message()
message['Content-Type'] = 'application/pgp-signature; name="signature.asc"'
message['Content-Description'] = 'OpenPGP digital signature'
message.set_payload(signature)
return message
gpg = gnupg.GPG()
basetext = basemsg.as_string().replace('\n', '\r\n')
signature = str(gpg.sign(basetext, detach=True, passphrase=gpg_passphrase))
if signature:
signmsg = messageFromSignature(signature)
msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha1",
protocol="application/pgp-signature")
msg.attach(basemsg)
msg.attach(signmsg)
msg['Subject'] = "Test message"
msg['From'] = "sender#example.com"
msg['To'] = "recipient#example.com"
print(msg.as_string(unixfrom=True)) # or send
else:
print('Warning: failed to sign the message!')
Note that here, I'm assuming a keyring with a passphrase, but you may not need that.
There are much more problem with the python built-in email library.
If you call the as_string procedure, the headers will be scanned for maxlinelength only in the current class, and in the childs (_payload) not! Like this:
msgRoot (You call `to_string` during sending to smtp and headers will be checked)
->msgMix (headers will be not checked for maxlinelength)
-->msgAlt (headers will be not checked for maxlinelength)
--->msgText (headers will be not checked for maxlinelength)
--->msgHtml (headers will be not checked for maxlinelength)
-->msgSign (headers will be not checked for maxlinelength)
I have signed msgMix.to_string() and then attached the signed message to the msgRoot. But during sending to the SMTP the msgMix part was different, the headers in msgMix was not chucked. Ofc, the sign was invalid.
It has taken two days for me to understand everything.. Here is my code what works and I use for sending automatic emails:
#imports
import smtplib, gnupg
from email import Charset, Encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.message import Message
from email.generator import _make_boundary
#constants
EMAIL_SMTP = "localhost"
EMAIL_FROM = "Fusion Wallet <no-reply#fusionwallet.io>"
EMAIL_RETURN = "Fusion Wallet Support <support#fusionwallet.io>"
addr = 'some_target_email#gmail.com'
subject = 'test'
html = '<b>test</b>'
txt = 'test'
#character set
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
#MIME handlers
msgTEXT = MIMEText(txt, 'plain', 'UTF-8')
msgHTML = MIMEText(html, 'html', 'UTF-8')
msgRoot = MIMEMultipart(_subtype="signed", micalg="pgp-sha512", protocol="application/pgp-signature")
msgMix = MIMEMultipart('mixed')
msgAlt = MIMEMultipart('alternative')
msgSIGN = Message()
msgOWNKEY = MIMEBase('application', "octet-stream")
#Data
msgRoot.add_header('From', EMAIL_FROM)
msgRoot.add_header('To', addr)
msgRoot.add_header('Reply-To', EMAIL_FROM)
msgRoot.add_header('Reply-Path', EMAIL_RETURN)
msgRoot.add_header('Subject', subject)
msgMix.add_header('From', EMAIL_FROM)
msgMix.add_header('To', addr)
msgMix.add_header('Reply-To', EMAIL_FROM)
msgMix.add_header('Reply-Path', EMAIL_RETURN)
msgMix.add_header('Subject', subject)
msgMix.add_header('protected-headers', 'v1')
#Attach own key
ownKey = gpg.export_keys('6B6C0EBB6DC42AA4')
if ownKey:
msgOWNKEY.add_header("Content-ID", "<0x6B6C0EBB.asc>")
msgOWNKEY.add_header("Content-Disposition", "attachment", filename='0x6B6C0EBB.asc')
msgOWNKEY.set_payload(ownKey)
#Attaching
msgAlt.attach(msgTEXT)
msgAlt.attach(msgHTML)
msgMix.attach(msgAlt)
if ownKey:
msgMix.attach(msgOWNKEY)
#Sign
gpg = gnupg.GPG()
msgSIGN.add_header('Content-Type', 'application/pgp-signature; name="signature.asc"')
msgSIGN.add_header('Content-Description', 'OpenPGP digital signature')
msgSIGN.add_header("Content-Disposition", "attachment", filename='signature.asc')
originalSign = gpg.sign(msgMix.as_string().replace('\n', '\r\n').strip()).data
spos = originalSign.index('-----BEGIN PGP SIGNATURE-----')
sign = originalSign[spos:]
msgSIGN.set_payload(sign)
#Create new boundary
msgRoot.set_boundary(_make_boundary(msgMix.as_string()))
#Set the payload
msgRoot.set_payload(
"--%(boundary)s\n%(mix)s--%(boundary)s\n%(sign)s\n--%(boundary)s--\n" % {
'boundary':msgRoot.get_boundary(),
'mix':msgMix.as_string(),
'sign':msgSIGN.as_string(),
}
)
#Send to SMTP
s = smtplib.SMTP(EMAIL_SMTP)
s.sendmail(EMAIL_FROM, addr, msgRoot.as_string())
s.quit()

Categories