The Vercel/NextJS deployment does not delay the completion of the serverless function until the email is sent via Azure

Upon a user's registration, I am attempting to send a registration/account activation email. While the email sends successfully via Azure's email services when running on localhost, deployments on Vercel do not trigger the email (although the user is added to the database).

I have researched issues related to Vercel-hosted deployments and email sending problems, often stemming from serverless functions terminating prematurely upon receiving a response, before the email is sent out. Despite trying asynchronous function calls with await/async methods in Microsoft's Azure Email Communication services, I have not been able to achieve the desired behavior. Are there any suggestions or fixes for this specific problem?

Similar issue link

Main takeaways from the provided link:

  • Requests must be resolved within 10 seconds on the free tier (60 seconds for pro),
  • Vercel appears to terminate a serverless function immediately after receiving a response, potentially halting unfinished side effects.

The solution mentioned adding an await statement to the email sending process, but since Azure's email client includes

const poller = await emailClient.beginSend(emailMessage);
const result = await poller.pollUntilDone();

the entire operation should await completion before the function returns, ensuring that the email is sent before termination.

Below is the key part of the code responsible for sending emails found in the api/register/route.ts file.

export async function POST(
  request: Request, 
) {
  const connectionString = process.env['COMMUNICATION_SERVICES_CONNECTION_STRING'];
  const emailClient = new EmailClient(connectionString);

  async function main() {
    const emailMessage = {
      senderAddress: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fcb893b29388ae998c9085bc9a95ffbbc4b0e6bbb7b1">[email protected]</a>",
      content: {
          subject: ``,
          text: ``,
          html: ``,
      },
      recipients: {
          to: [{ address: user.email }], // rest of the code is omitted for brevity
      },
    };

    const poller = await emailClient.beginSend(emailMessage);
    const result = await poller.pollUntilDone();
    console.log("Email sent: %s", result);
  }

  main().catch(console.error);

  // setTimeout(() => { return NextResponse.json(user); }, 3000);
  return NextResponse.json(user);
}

I attempted using a timeout buffer before responding to allow time for the email to be sent before the serverless function ends, however, it resulted in an error being thrown and caught both here and in the outer caller of this api route.ts.

My expectation was for the email to be successfully sent before the serverless function terminates, although errors were encountered during the process.

"error TypeError: Cannot read properties of undefined (reading 'headers') at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:261:61)"

Answer №1

Resolved the issue by including await before main().catch(console.error); since main is an asynchronous function being invoked within the overarching POST request.

Initial code snippet:

main().catch(console.error);

The updated code looks like this:

await main().catch(console.error);

This adjustment ensures that the function continues to execute until the email is successfully delivered.

In the context of user registration, it may be beneficial to separate the email sending process from the user registration/insertion into the database logic as it can cause delays in closing the registration modal while waiting for the email to dispatch. Placing the email sending functionality after the user creation in the database and modal closure would likely yield a smoother user experience.

axios.post("/api/register", data)
  .then((response) => {
    if (response.data.error) {
      toast.error(response.data.error.message);
    } else {
      toast.success(`Registration successful! Please verify your email to activate your account.`, {
        duration: 6000,
      });
      setStep(STEPS.BASICS)
      registerModal.onClose();
      loginModal.onOpen();
    }
  })
  .catch((error) => {
    if (error.response && error.response.data && error.response.data.error) {
      toast.error(error.response.data.error);
    } else {
      toast.error('Failed to complete registration. Please try again.');
    }
  })
  .finally(() => {
    setIsLoading(false);
  });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Developing an e-commerce website using Next.js for backend implementation

It's been bugging me - how do e-commerce websites figure out when a customer has placed an order? As I continue to learn front-end development with hopes to become full stack, the technical details behind this process intrigue me. Trying to wrap my he ...

Developing a user interface that filters out a specific key while allowing all other variable keys to be of the identical type

As I dive deeper into the TypeScript type system, I find myself grappling with an interface design query. Can anyone lend a hand? My goal is to craft an interface in TypeScript where certain object keys are of a generic type and all other keys should be o ...

Issue with prop inheritance in componentInheritance problem with passing props to

How can I pass the state function setMyChoice as a prop to the GamePlay component in a rock paper scissors Nextjs application? The goal is to produce a value for comparison. In the Gameplay component, I then pass a prop to another component called PlayButt ...

Tips for dynamically expanding the interface or type of an object in TypeScript

Currently, I am exploring the integration of PayPal's Glamorous CSS-in-JS library into a boilerplate project that also utilizes TypeScript. Glamorous provides a way to incorporate props into an element as shown below: const Section = glamorous.secti ...

Troubleshooting error in Next.js when adding "sizes" attribute to Image component with layout set to "responsive"

When you use the following code: <Image src="/images/lorem.jpg" height={150} width={850} layout="responsive" sizes="50vw" // <== ...

Using a component as a route in Next.js: A step-by-step guide

I am interested in creating a feature that resembles the popups on Facebook, where dynamic content such as images and text are displayed. When clicking on an item, I would like a popup to appear with a URL structure similar to /post/343542. Currently, I h ...

Can you explain the meaning of the code snippet: ` <TFunction extends Function>(target: TFunction) => TFunction | void`?

As I delve into the contents of the lib.d.ts file, one particular section caught my attention: declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void; The syntax in this snippet is a bit perplexing to m ...

Determining function return property type in Typescript by mapping interface argument property

In order to manage messaging between the browser and a web worker, I have developed a generic class. Each side creates a class that can send specific messages and acknowledge them on the other side with a returned result in a payload. The implementation is ...

Error encountered during Angular unit testing: Unable to read the 'id' property of a null value. (Jasmine, Karma)

I am currently working on writing unit tests for a specific component in my Angular application. The component uses a currentUser variable both in the component logic and the HTML template. I have hardcoded this variable by mocking it in every test using c ...

The template is displaying the string as "[object Object]"

I've implemented code in my ngOnInit function to fetch the translation for a specific text. The following function is being called: async getEmailTranslation() { const email$ = this.translate.get('SUPPORT_TRANSLATE.EMAIL'); this.emai ...

Guidelines for Nestjs class-validator exception - implementing metadata information for @IsNotIn validator error handling

I have a NestJs data transfer object (dto) structured like this import { IsEmail, IsNotEmpty, IsNotIn } from 'class-validator'; import { AppService } from './app.service'; const restrictedNames = ['Name Inc', 'Acme Inc&ap ...

Starting up a pre-existing Angular project on your local machine

I am completely new to Angular and facing difficulties running an existing project on my machine. Despite conducting numerous tests and following various articles, I still cannot get the project to run. Here is the layout of my project files: https://i.s ...

How to handle an already initialised array in Angular?

I came across an interesting demo on exporting data to Excel using Angular 12. The demo can be found at the following link: This particular example utilizes an array within the component TypeScript file. import { Component } from '@angular/core' ...

What is the best way to create an assertion function for validating a discriminated union type in my code?

I have a union type with discriminated properties: type Status = { tag: "Active", /* other props */ } | { tag: "Inactive", /* other props */ } Currently, I need to execute certain code only when in a specific state: // At some po ...

"Sending form data to an API using AMP Next.js through Axios: A Step-by-Step

I am currently working on my next amp project and encountering an issue where, upon hitting submit, the correct data is sent but the authentication headers are not being set on the request. I have Axios set up to include these headers in every request, so ...

Guide on mocking next-auth version 5 in a Next.js app with Jest

I recently upgraded to next-auth v5 in my nextjs project, but I'm having trouble mocking next-auth for testing the login functionality using jest. Below is a snippet of my ./auth.ts file: import NextAuth from 'next-auth'; import authConf ...

Sending information from a parent component to a child component within an Angular application

How can I efficiently pass the this.formattedBookingPrice and this.formattedCheckingPrice values to a child component using the value array instead of static values, especially when they are inside the subscribe method? This is my parent component. expor ...

Arrange a JavaScript map based on its values and ensure that a specific field index remains at the top position

I'm sure this question may seem simple to some, but as a JavaScript novice, I couldn't find the answer myself. Here is the code snippet I'm working with: Let map = new Map<String,String> map.set('0', select) map.set('1&a ...

support for fullscreenchange event across different browsers

I have been exploring how to add an event listener for fullscreen change in my Next.js app, and I noticed that many example codes use the webkit, moz, and ms prefixes together. However, after testing on Edge, Chrome, and Firefox, it seems that using only t ...

Navigating an object in TypeScript: the right approach

Curious if there might be a bug in TypeScript? Just seeking clarification on whether my code is incorrect or if there is an actual issue with the language. interface Something { key1: string; key2: number; key3: boolean; } const someObject: S ...