Sending an email from a background task

I have a resource hungry app which I’ve made to run in the background to avoid the 30s kill time. Is there any way that I can make an user not wait until the calculation in the background task finishes by calling the background task in the server code itself and just sending them a rendered pdf in an email once it completes?

All help appreciated.

Welcome to Anvil!

You don’t have to wait for the result of the background task in the client. You can, if you want to, poll it for the result, or I see no reason why you can’t just have the background task (which runs on the server) send the email as you suggest once it completes.

If you have a specific issue when testing that, let us know and someone can help.

Suggested reading :

https://anvil.works/docs/background-tasks/communicating-back

2 Likes

Yes, I do something similar to send an order confirmation email with an attached PDF. The biggest hurdle that I ran into was that I had to call a server function that then created the background task. Here’s some example code with the email addresses scrubbed… The PDF renderer occasionally throws an error–catching exceptions and sending myself an email if that happens.

@anvil.server.background_task
def order_conf_email(order_id, store_code, total_cost):
  print("order_conf_email")
  file_name = str(order_id)+".pdf"
  try:
    pdf = anvil.pdf.PDFRenderer(scale=0.75, page_size='Letter', filename=file_name).render_form("OrderEmail", order_id=order_id)
  except Exception as e:
    anvil.email.send(to='',
            from_address= "",
            from_name="",
            html=f"""Scheduled Task function_name encountered an error.
                         \n{traceback.format_exc()}""")
    raise Exception(traceback.format_exc())
    
#   store = app_tables.stores.get(Code=store_code)
  order = app_tables.orderheader.get(OrderID=order_id)
  email_list = ['',]
  sp_email = order['SalesPerson']['email']
  print(sp_email)
  if len(sp_email) > 6:
    email_list.append(sp_email)
  store = order['Store']
  if store['AdditionalEmails'] is not None:
    add_emails = store['AdditionalEmails'].split(',')
    email_list.extend(add_emails)
  print(email_list)
  anvil.email.send(
    to=', '.join(str(e) for e in set(email_list)),
    from_address= "",
    from_name="",
    subject="Order Confirmation: " + str(order_id) + " for Store " + store_code,
    html="TotalCost: " + str(round(total_cost,2)) + ".<br> Attached is a PDF copy of your order.  If you have any questions, please don't hesitate to reach out to us at 1-800-556-3695 or wholesale@stantt.com. ",
    attachments=pdf
  )

  
@anvil.server.callable
def start_order_conf_email(order_id, store_code, total_cost):
  print("start_order_conf_email")
  task = anvil.server.launch_background_task('order_conf_email', order_id, store_code, total_cost)
  print(task.get_id())
  return task
1 Like

I’ve carried out something similar and is working correctly. Fortunately I’ve not run into any random errors yet. Cheers.

1 Like

Glad to hear you’ve got something you’re happy with now! I’ve popped this thread into Q&A so other people can find it in future. You can also go ahead and mark this as ‘solved’ if you’re satisfied :smile: