Cannot set recipients - O365 - python

I'm trying to send e-mail using O365
However I could not find a way to set the Recipient withouth accessing a private attribute.
from O365 import *
my_protocol = MSGraphProtocol(api_version='beta')
account = Account(
credentials=('id', 'id'),
protocol=my_protocol
)
if not account.is_authenticated: # will check if there is a token and has not expired
# ask for a login
account.authenticate(scopes=['mailbox', 'message_send'])
msg = Message(parent=account)
msg.body = 'Hi, foobar.'
msg.subject = 'Bar Foo'
msg.to = Recipient(address='foobar#outlook.com', name='lucas') # dont work
msg._Message__to._recipients = [Recipient(address='foobar#outlook.com', name='lucas')] # works but very bad way i supossed
msg.setRecipients(Recipient(address='foobar#outlook.com', name='lucas')) # some old tutorials used this, but dont work either
msg.send()
This must be a very stupid question, but I read the classes from the doc and could not find a setter for the recipient.
Thanks!

Found it in the github.
msg.to.add('email')
This function add a recipient. Or many if you pass a list of strings.
Final code:
from O365 import *
my_protocol = MSGraphProtocol(api_version='beta')
account = Account(
credentials=('id', 'id'),
protocol=my_protocol
)
if not account.is_authenticated: # will check if there is a token and has not expired
# ask for a login
account.authenticate(scopes=['mailbox', 'message_send'])
msg = Message(parent=account)
msg.body = 'Hi, foobar.'
msg.subject = 'Bar Foo'
msg.to.add('foobar#outlook.com')
msg.send()

Related

how to use win32com.mapi get new email from outlook in python?

I wanna get a message when a new email into outlook.
I try to use python.
I can find that folders,but can't find the way to get the number of new email.
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
accounts = win32com.client.Dispatch("Outlook.Application").Session.Accounts;
inbox = outlook.Folders(accounts[0].DeliveryStore.DisplayName)
for obj in inbox.Folders: #how to know how many new email in this dir?
try:
if hasattr(obj, "__str__"):
dirName = obj.__str__() #as some new email in this obj.
for message in obj.items: # how to know this email is not be read ?
subject = sender = ''
if hasattr(message, "Subject"):
subject = message.Subject
if hasattr(message, "SenderName"):
sender = message.SenderName
print(sender, subject)
except Exception as e:
print(f"i:{obj.__str__()}")
and where can I learn win32com.mapi?
I wanna know what func can I use in mapi.
give me some info,please~
so much thanks!
Are you looking for unread messages? Use MAPIFolder.Items.Restrict("[Unread] = true") to retrieve Items collection with the restriction applied.

AWS Lambda unable to send email through AWS SES

I have verified the following
AWS SES isn't in Sandbox. I can send email via console to non-verified email ids.
My Lambda function has a role attached with full access to SES and Lambda (since its initial basic testing gave full permissions)
The following below a basic code from AWS documentation, just hard coded my email id. Yet I can't receive any email. The lambda code runs successfully but I don't receive emails.
import json
import os
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
#print("value1 = " + event['key1'])
#print("value2 = " + event['key2'])
#print("value3 = " + event['key3'])
#return event['key1'] # Echo back the first key value
#raise Exception('Something went wrong')
SENDER = "[redacted email]"
RECIPIENT = event['email']
CONFIGURATION_SET = "ConfigSet"
AWS_REGION = "us-east-2"
SUBJECT = "Contact Us Form Details"
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file for a list of customers to contact.</p>
</body>
</html>
"""
# The character encoding for the email.
CHARSET = "utf-8"
# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name='us-east-2')
# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = "Contact Us Form Details"
msg['From'] ="[redacted email]"
msg['To'] = "[redacted email]"
# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')
# Encode the text and HTML content and set the character encoding. This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)
# Define the attachment part and encode it using MIMEApplication.
#att = MIMEApplication(open(ATTACHMENT, 'rb').read())
# Add a header to tell the email client to treat this part as an attachment,
# and to give the attachment a name.
#att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))
# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)
# Add the attachment to the parent container.
#msg.attach(att)
print(msg)
try:
#Provide the contents of the email.
response = client.send_raw_email(
Source="[redacted email]",
Destinations=[
"[redacted email]"
],
RawMessage={
'Data':msg.as_string(),
},
#ConfigurationSetName=CONFIGURATION_SET
)
# Display an error if something goes wrong.
except ClientError as e:
print(e.response['Error']['Message'])
else:
print("Email sent! Message ID:"),
print(response['MessageId'])
Attaching my cloud watch logs for reference
If your code is really what you have displayed to us, then the reason that it is not sending the email is because half your code is not being executed.
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
#print("value1 = " + event['key1'])
#print("value2 = " + event['key2'])
#print("value3 = " + event['key3'])
#return event['key1'] # Echo back the first key value
#raise Exception('Something went wrong')
SENDER = "[redacted email]"
RECIPIENT = event['email']
CONFIGURATION_SET = "ConfigSet"
AWS_REGION = "us-east-2"
SUBJECT = "Contact Us Form Details"
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
When AWS Lambda executes the function, it calls lambda_handler(). As per Python formatting, it will execute all indented lines since they form part of the function. This includes your print() statement.
However, starting with the BODY_TEXT = ... line, there is no indenting. This means that the code is part of the "main" program, and not part of the lambda_handler() function. It would be executed when the Lambda container is first instantiated, but not when the function is triggered.
Bottom line: If this is your actual code, you need to fix your indents.
If you are not getting any errors from when executing the lambda, then most probably you are not hitting the SES API. From what I see in your code, you are missing an Access Key Id and Secret Access Key. Try configuring your boto client like this:
client = boto3.client(
'ses',
region_name=region,
aws_access_key_id='aws_access_key_string',
aws_secret_access_key='aws_secret_key_string'
)
Also make sure that your lambda is deployed in the same region as your SES. I see you are using us-east-2.
Another discrepancy I see, which is also in the documentation is that in the official AWS documentation, Destinations is actually Destination. Try it without the 's'.
Can you also paste the cloudwatch logs for the lambda. I see it should print the message Id upon success. Does it?

Python automated Outlook email: change sender or default reply-to address

I'm using code similar to Steve Townsend's answer from this question: Send Outlook Email Via Python?
to send an email by running a python script. How can I edit the default reply-to address, so that when someone replies to the automated email it will get sent to a specific address? Alternatively, can I modify the address that the email is sent from? I tried to modify the Msg.SentOnBehalfOfName property but had no success with that. Note that the address is an alias so I can't log into the account in Outlook.
import win32com.client
def send_mail_via_com(text, subject, recipient, profilename="Outlook2003"):
s = win32com.client.Dispatch("Mapi.Session")
o = win32com.client.Dispatch("Outlook.Application")
s.Logon(profilename)
Msg = o.CreateItem(0)
Msg.To = recipient
Msg.CC = "moreaddresses here"
Msg.BCC = "address"
Msg.Subject = subject
Msg.Body = text
attachment1 = "Path to attachment no. 1"
attachment2 = "Path to attachment no. 2"
Msg.Attachments.Add(attachment1)
Msg.Attachments.Add(attachment2)
Msg.Send()
You can try the following code to choose sender address and recipient address freely.
import win32com.client as win32
def send_mail():
outlook_app = win32.Dispatch('Outlook.Application')
# choose sender account
send_account = None
for account in outlook_app.Session.Accounts:
if account.DisplayName == 'sender#hotmail.com':
send_account = account
break
mail_item = outlook_app.CreateItem(0) # 0: olMailItem
# mail_item.SendUsingAccount = send_account not working
# the following statement performs the function instead
mail_item._oleobj_.Invoke(*(64209, 0, 8, 0, send_account))
mail_item.Recipients.Add('receipient#outlook.com')
mail_item.Subject = 'Test sending using particular account'
mail_item.BodyFormat = 2 # 2: Html format
mail_item.HTMLBody = '''
<H2>Hello, This is a test mail.</H2>
Hello Guys.
'''
mail_item.Send()
if __name__ == '__main__':
send_mail()
If you are interesting, you can refer this case.

Emails to recipients are not being sent using docusign sender view api where status is changed to sent

This is my sender view from where i create envelope as draft and open it in edit sender view and send it but recipients are not getting emails
#app.route('/sender', methods = ['POST'])
def sender1():
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
filename1 = pdf2.save(request.files['file'])
subject = request.form['subject']
body = request.form['body']
path1 = pdf2.path(filename1)
url1 = pdf2.url(filename1)
remoteFile1 = urllib.request.urlopen(url1).read()
login_information = client.login_information()
signers = [
models.Signer(
email=email,
name=name,
recipientId=1,
clientUserId=str(uuid.uuid4()), # Something unique in your database.
emailSubject=subject,
emailBody=body,
supportedLanguage='en')]
session['email']=email
session['name']=name
session['subject']=subject
session['body']=body
with open(path1, 'rb') as pdf:
envelope = models.Envelope(
documents=[
models.Document(
name='document.pdf',
documentId=1,
data=pdf,
)
],
emailSubject=subject,
emailBlurb='request for signing',
status=models.Envelope.STATUS_CREATED,
recipients=signers,
)
client.create_envelope_from_documents(envelope)
url = client.sender_edit_view(envelope.envelopeId)
models.Envelope(status=models.Envelope.STATUS_SENT)
data=url['url']
#data = data.replace('send=1','send=0')
#print(data)
return redirect(data)
This is the sender edit view to call api
def sender_edit_view(self,envelopeId=''):
"""POST to {account}/envelopes/{envelopeId}/views/recipient.
This is the method to start embedded signing for recipient.
Return JSON from DocuSign response.
"""
authenticationMethod=None
returnUrl='http://127.0.0.1:5000/callback'
if not self.account_url:
self.login_information()
url = '/accounts/{accountId}/envelopes/{envelopeId}/views/correct' \
.format(accountId=self.account_id,envelopeId=envelopeId,
)
if authenticationMethod is None:
authenticationMethod = 'email'
data = {
'authenticationMethod': authenticationMethod,
'returnUrl': returnUrl,
}
return self.post(url, data=data, expected_status_code=201)
How can i send email to recipients using the api. i have tried using the create correct api also and tried to update recipients but emails are still not being sent.
The problem isn't the sender view, the problem is that the signer is being marked as an embedded signer (no email invite to the signing ceremony is sent).
Your recipients aren't receiving email invitations because you are setting the clientUserId attribute for them.
Setting clientUserId causes a number of effects:
The signer becomes an embedded signer.
An email invitation to a signing ceremony is not sent.
The signer will sign via an embedded signing ceremony after you create one for them.
The metadata of the value of the clientUserId setting is maintained with the signer for your app's purposes.
To solve the problem:
Don't set the clientUserId attribute
If you want to maintain metadata between the receipient record in DocuSign and your own app, use the recipient's customFields attribute.
(This doesn't apply in your use case since you're using a uuid. But it may apply to other readers of this answer.)

Define mailbox to which to save an email - win32client python

I would like to save an email to the drafts folder of a shared mailbox using the win32 API for Outlook. I can save an email to my (default?) mailbox drafts folder using the below:
def TestEmailer(text, subject, recipient):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = recipient
mail.Subject = subject
mail.HtmlBody = text
mail.Save()
TestEmailer('hello world', 'test', 'recipient#gmail.com')
Thanks to this previous question I can see that the SendUsingAccount() method can be used to send from a defined mailbox. Is there an equivalent method for saving to the drafts folder of a defined mailbox?
You can select Save () when you switch your account to send email, which will be saved in the draft box of the new account.
Code:
import win32com.client as win32
def send_mail():
outlook_app = win32.Dispatch('Outlook.Application')
# choose sender account
send_account = None
for account in outlook_app.Session.Accounts:
if account.DisplayName == 'sender#hotmail.com':
send_account = account
break
mail_item = outlook_app.CreateItem(0) # 0: olMailItem
# mail_item.SendUsingAccount = send_account not working
# the following statement performs the function instead
mail_item._oleobj_.Invoke(*(64209, 0, 8, 0, send_account))
mail_item.Recipients.Add('receipient#outlook.com')
mail_item.Subject = 'Test sending using particular account'
mail_item.BodyFormat = 2 # 2: Html format
mail_item.HTMLBody = '''
<H2>Hello, This is a test mail.</H2>
Hello Guys.
'''
mail_item.Save()
if __name__ == '__main__':
send_mail()
Here's a bit of black magic here. Setting mail_item.SendUsingAccount directly won't work. The return value is none. Always send mail from the first email account. You need to call the method of oleobj_.Invoke().
Updated:
Oleobj document: https://github.com/decalage2/oletools/wiki/oleobj
Similar case: python win32com outlook 2013 SendUsingAccount return exception

Categories