msgraph-sdk-python icon indicating copy to clipboard operation
msgraph-sdk-python copied to clipboard

Example 8 from examples doesn't work

Open WardenHub opened this issue 2 years ago • 13 comments

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

image

WardenHub avatar Oct 02 '23 15:10 WardenHub

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.

danielniccoli avatar Oct 02 '23 15:10 danielniccoli

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 from msgraph.generated.send_mail.send_mail_post_request_body import SendMailPostRequestBody ModuleNotFoundError: No module named 'msgraph.generated.send_mail'

WardenHub avatar Oct 03 '23 07:10 WardenHub

@WardenHub Example 8 does not have a line that looks like:

from msgraph.generated.send_mail.send_mail_post_request_body import SendMailPostRequestBody

danielniccoli avatar Oct 03 '23 09:10 danielniccoli

@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'

WardenHub avatar Oct 03 '23 09:10 WardenHub

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.

danielniccoli avatar Oct 03 '23 10:10 danielniccoli

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?

WardenHub avatar Oct 03 '23 10:10 WardenHub

Well, this one: ModuleNotFoundError: No module named 'msgraph.generated.me' :)

danielniccoli avatar Oct 03 '23 18:10 danielniccoli

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

WardenHub avatar Oct 04 '23 07:10 WardenHub

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;">&#128512;</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())

WardenHub avatar Oct 04 '23 09:10 WardenHub

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.

WardenHub avatar Oct 04 '23 12:10 WardenHub

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!

sebeyza00 avatar Dec 08 '23 15:12 sebeyza00

from msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody

This one worked for me

nrnw avatar May 28 '24 13:05 nrnw

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())

tiborrr avatar Aug 29 '24 07:08 tiborrr