Search code examples
djangodjango-rest-frameworkdjango-viewsoutlookpywin32

"Waiting list" or delay when sending emails with Django and the win32 library


I have just discovered something in the provided code, and I would like to explain it to you. During my tests with the email sending using this code, everything seemed to work correctly, but a specific issue arose.

Let's say I have three emails to send: email 1, email 2, and email 3. When I send email 1, the console returns a 200 OK status, but the email doesn't reach my inbox. Then, when I proceed to send email 2, the console again returns a 200 OK status, and although a new email appears in my inbox, it turns out to be email 1. After waiting several minutes without receiving any updates or new emails, I proceed to send email 3. At this point, the console once again shows a 200 OK status, and, surprisingly, I receive a new email in my inbox, but now it is email 2.


   class ApiSendMailCreateNewReporter(APIView):
    def get(self, request, id_headerRequest):
        try:
            # Obtener el objeto HeaderRequest o devolver un error 404 si no existe
            header_request = get_object_or_404(HeaderRequest, id=id_headerRequest)

            # Serializar el objeto HeaderRequest
            serializer_header_request = HeaderRequestSerializer(header_request)
            usuario_id = serializer_header_request.data['id_user_id']
            require_date = serializer_header_request.data['require_date']
            customer = serializer_header_request.data['customer']

            # Obtener la instancia de Engineers con role='admin' o devolver un error 404 si no existe
            engineer_instance = get_object_or_404(Engineers, role='admin')
            engineer_serializer = EnginnerAdminSerializer(engineer_instance)
            admin_email = engineer_serializer.data['email']

            # Obtener la instancia de Users o devolver un error 404 si no existe
            user_instance = get_object_or_404(Users, id=usuario_id)
            serializer_user = UserAccountsSerializer(user_instance)
            full_name = f"{serializer_user.data['first_Name']} {serializer_user.data['last_Name']}"

            # Inicializar el modelo de objetos COM
            pythoncom.CoInitialize()
            dynamic_link = 'xxxxxxxxxxxxxx'

            # Configurar el correo
            outlook = win32.Dispatch('Outlook.Application')
            mail = outlook.CreateItem(0)
            mail.SentOnBehalfOfName = '[email protected]'
            mail.To = admin_email
            mail.Subject = 'NUEVA SOLICITUD DE PRUEBAS DE LABORATORIO'
            html_body = f"""
                <html>
                    <body>
                        <div>
                            <h1>Nueva solicitud de pruebas de laboratorio de {full_name}</h1>
                            <p>El usuario {full_name} ha creado una nueva solicitud de pruebas de laboratorio para el cliente {customer} con una fecha requerida para el {require_date}</p>
                            <a href="{dynamic_link}">
                                Ir al Sitio
                            </a>
                        </div>
                    </body>
                </html>
            """
            mail.HTMLBody = html_body
            mail.Send()

            return Response({"message": "Correo enviado correctamente"}, status=status.HTTP_200_OK)

        except Exception as e:
            print(f"Error: {e}")
            return Response({"message": "Correo NO enviado correctamente"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        finally:
            # Liberar recursos
            pythoncom.CoUninitialize()

Due to the company's structure, I am unable to use SMTP server emails.


Solution

  • By calling the Send method from the Outlook object model you don't push the email to be sent immediately. The Send method submits the item for further processing. But the real processing will take its place when Outlook synchronizes its folders with the backend server (for example, Exchange).

    If you need to make sure that a particular submitted item is processed and sent out immediately right after calling the Send method you need to use the NameSpace.SyncObjects property which returns a SyncObjects collection containing all Send\Receive groups. The Start method begins synchronizing a user's folders using the specified Send\Receive group.

    For example, the following VBA sample shows how to push submitted items (use the Start method):

    Public Sub Sync()  
     Dim nsp As Outlook.NameSpace  
     Dim sycs As Outlook.SyncObjects  
     Dim syc As Outlook.SyncObject  
     Dim i As Integer  
     Dim strPrompt As Integer  
     Set nsp = Application.GetNamespace("MAPI")  
     Set sycs = nsp.SyncObjects  
     For i = 1 To sycs.Count  
       Set syc = sycs.Item(i)  
       syc.Start   
     Next  
    End Sub
    

    I am not familiar with python, but the VBA sample listed above shows the required method and properties to get the job done. The Outlook object model is common for all kind of programming languages.