Example 8 from examples doesn't work
Example 8 from the SDK does not work for me (direct copy paste). I get a ModuleNotFoundError: No module named 'msgraph.generated.send_mail' error.
I installed on python 3.10.9 with pip install msgraph-sdk without errors.pi
msgraph-core 1.0.0a4
msgraph-sdk 1.0.0a16
Full disclosure: I tried running ; pip install --upgrade 'msgraph-sdk @ git+https://github.com/microsoftgraph/msgraph-sdk-python.git'
to ensure I have the latest version but this gives me a load of filename too long errors
Example 8 from the SDK does not work for me (direct copy paste). I get a ModuleNotFoundError: No module named 'msgraph.generated.send_mail' error.
I don't get that error (I get a different one). Can you post the traceback?
to ensure I have the latest version but this gives me a load of filename too long errors
That's not a problem with the SDK. Stick to using the PyPi package.
Example 8 from the SDK does not work for me (direct copy paste). I get a ModuleNotFoundError: No module named 'msgraph.generated.send_mail' error.
I don't get that error (I get a different one). Can you post the traceback?
to ensure I have the latest version but this gives me a load of filename too long errors
That's not a problem with the SDK. Stick to using the PyPi package.
Traceback (most recent call last):
File "\Python310\lib\idlelib\run.py", line 578, in runcode
exec(code, self.locals)
File "POST mail GraphApi - sdk.py", line 6, in
@WardenHub Example 8 does not have a line that looks like:
from msgraph.generated.send_mail.send_mail_post_request_body import SendMailPostRequestBody
@WardenHub Example 8 does not have a line that looks like:
from msgraph.generated.send_mail.send_mail_post_request_body import SendMailPostRequestBody
Ah excuse me, I tried removing the .me. part from the example to see if that alleviated the issue - the original traceback was:
Traceback (most recent call last):
File "\Python\Python310\lib\idlelib\run.py", line 578, in runcode
exec(code, self.locals)
File "POST mail GraphApi - sdk.py", line 6, in <module>
from msgraph.generated.me.send_mail.send_mail_post_request_body import SendMailPostRequestBody
ModuleNotFoundError: No module named 'msgraph.generated.me'
It should be
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody
But I'd leave the ticket open for the example to be corrected.
Hey that's really helpfull,
I adapted the response to work with my secret token access and it actually sends the mail now!
versturende_email = '[email protected]'
response = await graph_client.users.by_user_id(versturende_email).send_mail.post(request_body)
def main():
asyncio.run(send_mail())
main()
if you change email_body.content_type = BodyType.Html it even accepts html as email_body.content .. so I'm good to go .. The documentation has been challenging though..
Thank you very much @danielniccoli
I do find myself wondering.. what error are you getting?
Well, this one: ModuleNotFoundError: No module named 'msgraph.generated.me' :)
Well, this one:
ModuleNotFoundError: No module named 'msgraph.generated.me':)
That's the thing you fixed for me! This is my full import statement that made example 8 work for me (with the above tweaking of the response code)
import asyncio
from azure.identity import ClientSecretCredential
from msgraph import GraphServiceClient
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody
from msgraph.generated.models.body_type import BodyType
from msgraph.generated.models.message import Message
from msgraph.generated.models.email_address import EmailAddress
from msgraph.generated.models.importance import Importance
from msgraph.generated.models.item_body import ItemBody
from msgraph.generated.models.recipient import Recipient
from msgraph.generated.users.item.messages.messages_request_builder import MessagesRequestBuilder
So replace
from msgraph.generated.me.send_mail.send_mail_post_request_body import SendMailPostRequestBody
with
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody
I also offer my 'final' anonymized script for sending multiple mails through the sdk for documentation / whomever may be looking for it. Thanks for your assistance @danielniccoli
import asyncio
from azure.identity import ClientSecretCredential
from msgraph import GraphServiceClient
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody
from msgraph.generated.models.body_type import BodyType
from msgraph.generated.models.message import Message
from msgraph.generated.models.email_address import EmailAddress
from msgraph.generated.models.importance import Importance
from msgraph.generated.models.item_body import ItemBody
from msgraph.generated.models.recipient import Recipient
from msgraph.generated.users.item.messages.messages_request_builder import MessagesRequestBuilder
#workaround 429 throttling error
import time
'''
Template Script 26-9-23 Graph API
See https://developer.microsoft.com/en-us/graph/graph-explorer for endpoint types
'''
# Send from email address
versturende_email = "[email protected]"
# Demo mode
demo = True
# Configuration
config = {
"client_id": "your_client_id_here",
"scope": ["https://graph.microsoft.com/.default"],
"secret": "your_client_secret_here",
"tenant_id": "your_tenant_id_here",
"authority": 'https://login.microsoftonline.com/your_tenant_id_here',
"eindpunt": 'https://graph.microsoft.com/v1.0/users/[email protected]/sendMail'
}
# Get token
scopes = ["https://graph.microsoft.com/.default"]
credential = ClientSecretCredential(
tenant_id=config["tenant_id"],
client_id=config["client_id"],
client_secret=config["secret"],
)
graph_client = GraphServiceClient(credentials=credential, scopes=scopes)
# HTML content with a smiley
html = """
<!DOCTYPE html>
<html>
<head>
<title>Smiley Face</title>
</head>
<body>
<div style="font-size: 48px; text-align: center;">😀</div>
</body>
</html>
""".replace("\n", "")
def create_mail(bericht_html: str, titel, ontvangers: list, cc_ontvangers: list = [], bcc_ontvangers: list = [], versturende_email="[email protected]"):
'''
Create a valid mail object to be sent using Microsoft Graph API.
Parameters:
- bericht_html (str): The HTML content of the email body.
- titel (str): The subject of the email.
- ontvangers (list): A list of recipient email addresses.
- cc_ontvangers (list, optional): A list of email addresses to be included in the CC field.
- bcc_ontvangers (list, optional): A list of email addresses to be included in the BCC field.
- versturende_email (str, optional): The email address of the sender.
Returns:
SendMailPostRequestBody: An object representing the mail to be sent.
'''
# Sender
sender = EmailAddress()
sender.address = versturende_email
from_recipient = Recipient()
from_recipient.email_address = sender
recipients = []
for ontvanger in ontvangers:
# Add recipient per recipient
recipient_email = EmailAddress()
recipient_email.address = ontvanger
to_recipient = Recipient()
to_recipient.email_address = recipient_email
recipients.append(to_recipient)
# CC
if cc_ontvangers != []:
cc_recipients = []
for cc_ontvanger in cc_ontvangers:
# Add cc_recipient per recipient
cc_recipient_email = EmailAddress()
cc_recipient_email.address = cc_ontvanger
cc_recipient = Recipient()
cc_recipient.email_address = cc_recipient_email
cc_recipients.append(cc_recipient)
# BCC
if bcc_ontvangers != []:
bcc_recipients = []
for bcc_ontvanger in bcc_ontvangers:
# Add bcc_recipient per recipient
bcc_recipient_email = EmailAddress()
bcc_recipient_email.address = bcc_ontvanger
bcc_recipient = Recipient()
bcc_recipient.email_address = bcc_recipient_email
bcc_recipients.append(bcc_recipient)
# Message body
email_body = ItemBody()
email_body.content = bericht_html
email_body.content_type = BodyType.Html
# Message object
message = Message()
message.subject = titel
message.from_escaped = from_recipient
message.to_recipients = recipients
if cc_ontvangers != []:
message.cc_recipients = cc_recipients
if bcc_ontvangers != []:
message.bcc_recipients = bcc_recipients
message.body = email_body
# Request object
request_body = SendMailPostRequestBody()
request_body.message = message
return request_body
async def send_mail(mailbericht):
try:
response = await graph_client.users.by_user_id(versturende_email).send_mail.post(mailbericht)
#workaround 429 throttling error
time.sleep(1)
# Print or handle the response here
except Exception as e:
print(e)
async def main():
naar = ["[email protected]"]
cc = []
bcc = []
mailbericht = create_mail(html, "Test Email Subject", naar, cc, bcc)
# Create a list of tasks to run concurrently
tasks = [send_mail(mailbericht) for _ in range(1, 5)]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
Short update from user case: above runs into error 429 throttling errors when bulk sending mails.
please provide / add an example for the function (or SDK) to innately handle the Retry-After: value that is returned in the response.
nice! i did want to ask how did you find these were the import statements you needed? seems really hard to find in the documentation!
from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody
This one worked for me
I had the same issue with throttling. Using a asyncio.Semaphore did the trick for me.
Below you find an example on how to use it.
import asyncio
from msgraph import GraphServiceClient
from azure.identity import ClientSecretCredential
# Define a semaphore with a maximum of 4 concurrent requests
graph_api_semaphore = asyncio.Semaphore(4)
async def get_user(client: GraphServiceClient, user_id: str):
async with graph_api_semaphore:
user = await client.users.by_user_id(user_id).get()
return user
async def main():
# Set up the GraphServiceClient (similar to the example in the docs)
credential = ClientSecretCredential(
tenant_id='TENANT_ID',
client_id='CLIENT_ID',
client_secret='CLIENT_SECRET'
)
scopes = ['https://graph.microsoft.com/.default']
client = GraphServiceClient(credentials=credential, scopes=scopes)
# List of user IDs to fetch
user_ids = ['user1', 'user2', 'user3', 'user4', 'user5', 'user6']
# Use asyncio.gather to run multiple requests concurrently
users = await asyncio.gather(*[get_user(client, user_id) for user_id in user_ids])
for user in users:
if user:
print(f"User: {user.display_name}, Email: {user.mail}")
if __name__ == "__main__":
asyncio.run(main())