skip to Main Content

I use form to verify the email with emailjs, sending the email value to next.js API. In the API route.js I create and hash token, store it in database and make a confirmation link(so far the console.logs are giving my that everything is ok) and then in the sendEmail (which I use in another form and it works)function I receive: "Email send failed: undefined
portfolio3d-nextjs-app-1 | Failed to send email: Error: Failed to send email
portfolio3d-nextjs-app-1 | at sendEmail (webpack-internal:".
Another info I use Docker image to run my project.
Can someone give me advice how to solve this problem?

'use client';
import React from 'react';
import { useForm } from 'react-hook-form';
import { Toaster, toast } from 'sonner';
import { MailCheck, MailX } from 'lucide-react';

export default function EmailConfirmationForm() {
    const { register, handleSubmit, formState: { errors }, reset } = useForm();

    // Send confirmation email
    const handleSendConfirmationEmail = async (email) => {
        try {
            const response = await fetch(`/api/sendConfirmationEmail?email=${email}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ email }),
            });
            if (!response.ok) throw new Error('Failed to send confirmation email');
            toast.success('Confirmation email sent!', {
                duration: 5000,
                icon: <MailCheck />,
                style: {
                    backgroundColor: '#1B1B1B',
                    border: 'none',
                },
            });
            return true;
        } catch (error) {
            toast.error('Failed to send confirmation email.', {
                duration: 5000,
                icon: <MailX />,
                style: {
                    backgroundColor: '#1B1B1B',
                    border: 'none',
                },
            });
            return false;
        }
    };

    const onSubmit = async (data) => {

        try {
            await handleSendConfirmationEmail(data.email);

            reset(); 
        } catch (error) {
            console.error('Failed to send confirmation email:', error);
        }
    };

    return (
        <>
            <Toaster position="bottom-left" richColors />
            <form onSubmit={handleSubmit(onSubmit)} className="max-w-md w-full flex flex-col items-center justify-center space-y-4">

                {/* Email input */}
                <label htmlFor="email" className="self-start">Email Confirmation</label>
                <input
                    id="email"
                    type="email"
                    placeholder="Email Confirmation"
                    {...register("email", {
                        required: 'This field is required',
                        pattern: { value: /^S+@S+$/i, message: 'Invalid email format' }
                    })}
                    className="w-full p-2 rounded-md shadow-lg text-foreground focus:outline-none focus:ring-2 focus:ring-accent/50 custom-bg"
                    aria-label="Email"
                />
                {errors.email && <span className="inline-block self-start text-red-500">{errors.email.message}</span>}

                <input
                    value="Cast your message!"
                    className="px-10 py-4 rounded-md shadow-lg bg-background border border-accent/30 hover:shadow-glass-sm backdrop-blur-sm text-foreground focus:outline-none focus:ring-2 focus:ring-accent/50 cursor-pointer capitalize"
                    type="submit"
                />
            </form>
        </>
    );
}
import { NextResponse } from 'next/server';
import { sendEmail } from '@/app/../../service/service.email';
import redisClient, { connectRedis } from '@/app/../../service/redisClient';
import { generateToken, hashToken } from '@/app/../../service/tokenService';
import { rateLimiter } from '@/app/../../service/rateLimiter';

export async function POST(req) {
    const { searchParams } = new URL(req.url);
    const email = searchParams.get('email');
    const ip = req.headers.get('x-forwarded-for') || req.socket.remoteAddress || req.ip;

    // if (!rateLimiter(ip)) {
    //     return NextResponse.json({ message: 'Too many requests, please try again later.' }, { status: 429 });
    // }

    await connectRedis();

    const token = generateToken();
    const hashedToken = await hashToken(token);

    const expiresAt = Date.now() + 3600 * 1000;

    try {
        await redisClient.setEx(`confirm_tokens:${hashedToken}`, 3600, JSON.stringify({ email, expiresAt }));
        const storedToken = await redisClient.get(`confirm_tokens:${hashedToken}`);
        console.log('Token stored in Redis:', storedToken); // Log to verify storage
    } catch (redisError) {
        console.error('Error saving token in Redis:', redisError);
        return NextResponse.json({ message: 'Error saving confirmation token to Redis.' }, { status: 500 });
    }

    const confirmationLink = `${process.env.NEXT_PUBLIC_APP_URL}/api/confirmEmail?token=${token}&email=${email}`;
    console.log(`Confirmation link: ${confirmationLink}`);
    try {
        const templateParams = {
            to: email,
            from_name: 'Email Confirmation',
            reply_to: email,
            message: `Please confirm your email by clicking the link: ${confirmationLink}`,
        };

        await sendEmail(templateParams);

        return NextResponse.json({ message: 'Confirmation email sent!' }, { status: 200 });
    } catch (error) {
        console.error('Failed to send email:', error);
        return NextResponse.json({ message: 'Failed to send confirmation email.' }, { status: 500 });
    }
}
import emailjs from '@emailjs/browser';

export const sendEmail = async (params) => {
    try {
        const response = await emailjs.send(
            process.env.NEXT_PUBLIC_SERVICE_ID,
            process.env.NEXT_PUBLIC_TEMPLATE_ID,
            params,
            {
                publicKey: process.env.NEXT_PUBLIC_PUBLIC_KEY,
                limitRate: {
                    throttle: 5000,
                },
            }
        );
        console.log('Email sent successfully:', response);
        return response;  
    } catch (error) {
        console.error('Email send failed:', error.text);
        if (error.response) {
            console.error('Error response from email service:', error.response);
        }
        throw new Error(error.text || 'Failed to send email');
    }
};

2

Answers


  1. I think you are using this node package on server side ‘@emailjs/browser’. while this is used for client side only.
    please use this package https://www.npmjs.com/package/@emailjs/nodejs on server side code.

    Login or Signup to reply.
  2. EmailJs expects a specific format. Try updating the key value pairs as follows:

    to_email: email, 
    from_name: 'Email Confirmation',
    to_name: email.split('@')[0],  
    message: `Please confirm your email by clicking the link: ${confirmationLink}`
    

    change "to" to "to_email" and set "reply_to" to "to_name".

    If this doesnt work, make sure your environment variables are properly set in docker and also consider adding logging to help debug errors.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search