sabuhish / fastapi-mail

Fastapi mail system sending mails(individual, bulk) attachments(individual, bulk)
https://sabuhish.github.io/fastapi-mail/
MIT License
698 stars 81 forks source link

send_message as background task is not working #120

Closed pepegc closed 2 years ago

pepegc commented 2 years ago

Mails are not going out in background.

We have backgrounds tasks working well in other endpoints. Any idea of what could be the issue?

We tried without a template (exactly like your example) and it does not work either.

class SigninEmailSchema(BaseModel):
    recipient: EmailStr
    a: str
    b: str

@router.post('/email/signin')
async def send_signin_email(
        bg: BackgroundTasks,
        contents: SigninEmailSchema,
    ) -> JSONResponse:

    message = MessageSchema(
        subject = ' subject ',
        recipients = [contents.recipient],
        template_body = {
            'a': contents.a,
            'b': contents.b,
        },
    )

    fm = FastMail(conf)

    #await fm.send_message(message, template_name='signin.html') # WORKS
    bg.add_task(fm.send_message, message, template_name='signin.html') # DOES NOT WORK

    return JSONResponse(
        status_code=200,
        content = {'message': 'email was sent'},
)
AlparslanKaraguney commented 2 years ago

I have the same problem did anyone find a solution for this.

ramiswailem commented 2 years ago

how do you run the app? Uvicorn? Hypercorn? and which worker class are you use? can you switch between them?

pepegc commented 2 years ago

hey @ramiswailem, I'm using uvicorn: uvicorn app.main:app --reload. Not sure what you mean by the worker class so I guess it's whatever the default is

ramiswailem commented 2 years ago

can you test it with:

gunicorn main:app -k uvicorn.workers.UvicornWorker

or with:

pip install hypercorn[uvloop] hypercorn main:app --worker-class uvloop

sabuhish commented 2 years ago

Hi, this issue is solved in the new version of fastapi-mail, please install 1.0.9 version.

pepegc commented 2 years ago

I was on 1.0.6. I tried it now with 1.0.9 and it's still the same. What about you @AlparslanKaraguney ?

sabuhish commented 2 years ago

Once I upgraded to 1.0.9 it was totally working, I was able to send with background task. Can you try, or could you tell me how you run it?

@app.get("/email")
async def send_in_background(
    background_tasks: BackgroundTasks,

    ) -> JSONResponse:

    message = MessageSchema(
        subject="Fastapi mail module",
        recipients=["mail_address"],
        body="Simple background task",
        )

    fm = FastMail(conf)

    background_tasks.add_task(fm.send_message,message)

    return JSONResponse(status_code=200, content={"message": "email has been sent"})

uvicorn app:app --port 8002 --reload

pepegc commented 2 years ago

The code I have is exactly what I wrote above (1st comment). Note the line that works (with await) and the one that does not (with add_task)

locally I run it with uvicorn app.main:app --reload in production I have it on heroku with uvicorn app.main:app --host=0.0.0.0 --port=${PORT:-5000}

vatsal-fpl commented 2 years ago

Yes I have also the same issue since yesterday. I have tested the background task in main.py and it's not working but when I created a separate file for with similar endpoint with different name it's working. Somehow it's not working in my main.py

vatsal-fpl commented 2 years ago

Update Guys check if you are using some kind of middleware. I was using the middleware to check request ip and when I removed it background tasks started running

sabuhish commented 2 years ago

Well, I dont know what you guys have a configuration in the application, but I checked maybe 5 with an HTML template, and without it (simple approach), it works finely.

vatsal-fpl commented 2 years ago

I am taking name as input from users and putting it into my html template. I have also updated the latest version.

https://sabuhish.github.io/fastapi-mail/example/

sabuhish commented 2 years ago

it does not matter, still, I dont see any error, please check each version of the libraries you are using. Try to use the debugger.

yubinees2 commented 2 years ago

I'm having the same issue on fastapi==0.78.0 and fastapi-mail==1.0.9. I tried like below:

@app.post('/email')
async def send_signup_email(background_tasks: BackgroundTasks, email_form: EmailFormModel, email_user:EmailUserModel, debug:bool=False):
    message = MessageSchema(
        subject=email_form.subject,
        recipients=[email_user.to],
        template_body={'title': email_form.title,
             'name': email_user.name,
             'content': email_form.params.get("content", "test email."),
             'link': email_form.params.get("link", "https://www.test.com")
               },
        subtype='html',
    )

    if debug:
        print(message)
        await fm.send_message(message, template_name='template.html')
    else:
        background_tasks.add_task(fm.send_message, message, template_name='template.html')

    return 'Success'

Both debug=True/False option results same 'Success' but only await fm.send_message() sended email. The interesting point is that the result with same backgroud_task.add_task works differently whether I called it through swaggerUI or curl -X POST, 0.0.0.0 or localhost, domain or internal ip. I guess it is likely to be related with uvicorn.

keremnymn commented 2 years ago

Exact same issue. await sends the mail but BackgroundTasksdoesn't.

uvicorn==0.17.6
fastapi==0.78.0
fastapi-mail==1.0.9
AsadBukharee commented 2 years ago

some of the guy are using asyncio as mentioned here. Can you figure out the reason. I was going to use fastapi-mail in my project but now I am double mined.

AsadBukharee commented 2 years ago

@sabuhish ,Is anybody working on this issue?

AlparslanKaraguney commented 2 years ago

I was on 1.0.6. I tried it now with 1.0.9 and it's still the same. What about you @AlparslanKaraguney ?

Sorry for late response. I did not test with 1.0.9 but i solved my problem by using celery worker. So in background task i use Celery to send the mail using fastapi mail.

AsadBukharee commented 2 years ago

I am also using celery worker now , in windows we need to use eventlet or solo as follows. pip install eventlet celery -A worker worker --loglevel=INFO -P eventlet

it seems irrelevant but it may save time for others.

jctissier commented 2 years ago

Did anyone get this working with FastAPI for the background task only (no celery)? I have the most recent updated packages for uvicorn, fastapi & fastapi-mail. It used to work on previous versions but not anymore

sabuhish commented 2 years ago

Hi There! I have tried many times, and still I don't have any issues with the same config as you have mentioned, I have been able to send emails with background tasks. Here is the configuration I have made and directories where my files lives.

I have created app.py file and templates folder, inside templates folder I have signin.html

app.py

from pathlib import Path
from typing import List

from fastapi import BackgroundTasks, FastAPI
from fastapi_mail import ConnectionConfig, FastMail, MessageSchema
from pydantic import BaseModel, EmailStr
from starlette.responses import JSONResponse

conf = ConnectionConfig(
    MAIL_USERNAME = "my_username",
    MAIL_PASSWORD = "my_password",
    MAIL_FROM = "from_name",
    MAIL_PORT = 465,
    MAIL_SERVER = "mail_server",
    MAIL_FROM_NAME="Name",
    MAIL_SSL = True,
    TEMPLATE_FOLDER = Path(__file__).parent / 'templates',
)

app = FastAPI()

class EmailSchema(BaseModel):
    recipient: EmailStr
    a: str
    b: str

@app.post('/email')
async def send_signin_email(
        bg: BackgroundTasks,
        contents: EmailSchema,
    ) -> JSONResponse:

    message = MessageSchema(
        subject = ' subject ',
        recipients = [contents.recipient],
        template_body = {
            'a': contents.a,
            'b': contents.b,
        },
    )

    fm = FastMail(conf)

    #await fm.send_message(message, template_name='signin.html') # WORKS ->this works
    bg.add_task(fm.send_message, message, template_name='signin.html') # DOES NOT WORK -> also works as expected

    return JSONResponse(
        status_code=200,
        content = {'message': 'email was sent'},
)

The background is just executed in either thread or just calls the async function:

https://github.com/encode/starlette/blob/master/starlette/background.py#L15

Apart from topics about background tasks that is not related to the fastapi-mail it is not part of the library, it is part of starlette, it is better to move the discussion there.