async sendMagicLink(options) {
        this.sentry?.captureMessage?.(`[Magic Link] Generating magic link`, {extra: options});

        if (!isEmail(options.email)) {
            throw new BadRequestError({
                message: tpl(messages.invalidEmail)
            });
        }

        const token = await this.tokenProvider.create(options.tokenData);

        const type = options.type || 'signin';

        const url = this.getSigninURL(token, type, options.referrer);

        const info = await this.transporter.sendMail({
            to: options.email,
            subject: this.getSubject(type),
            text: this.getText(url, type, options.email),
            html: this.getHTML(url, type, options.email)
        });

        return {token, info};
    }
sendMagicLink

@param {object} options
@param {string} options.email - The email to send magic link to
@param {TokenData} options.tokenData - The data for token
@param {string} [options.type='signin'] - The type to be passed to the url and content generator functions
@param {string} [options.referrer=null] - The referrer of the request, if exists. The member will be redirected back to this URL after signin.
@returns {Promise<{token: Token, info: SentMessageInfo}>}