Home / Function/ EmailTemplates() — supabase Function Reference

EmailTemplates() — supabase Function Reference

Architecture documentation for the EmailTemplates() function in EmailTemplates.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  631f2ac0_324c_b494_cb43_7312f07e0f88["EmailTemplates()"]
  e77ee66e_6e73_9fe9_e27e_c82c7419daa8["slugifyTitle()"]
  631f2ac0_324c_b494_cb43_7312f07e0f88 -->|calls| e77ee66e_6e73_9fe9_e27e_c82c7419daa8
  style 631f2ac0_324c_b494_cb43_7312f07e0f88 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx lines 60–330

export const EmailTemplates = () => {
  const { ref: projectRef } = useParams()
  const { can: canUpdateConfig } = useAsyncCheckPermissions(
    PermissionAction.UPDATE,
    'custom_config_gotrue'
  )

  const [acknowledged, setAcknowledged] = useLocalStorageQuery(
    LOCAL_STORAGE_KEYS.SECURITY_NOTIFICATIONS_ACKNOWLEDGED(projectRef ?? ''),
    false
  )

  const {
    data: authConfig,
    error: authConfigError,
    isPending: isLoading,
    isError,
    isSuccess,
  } = useAuthConfigQuery({ projectRef })

  const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation({
    onError: (error) => {
      toast.error(`Failed to update settings: ${error?.message}`)
    },
    onSuccess: () => {
      toast.success('Successfully updated settings')
    },
  })

  const builtInSMTP =
    isSuccess &&
    authConfig &&
    (!authConfig.SMTP_HOST || !authConfig.SMTP_USER || !authConfig.SMTP_PASS)

  const defaultValues = notificationEnabledKeys.reduce(
    (acc, key) => {
      acc[key] = authConfig ? Boolean(authConfig[key as keyof typeof authConfig]) : false
      return acc
    },
    {} as Record<string, boolean>
  )

  const notificationsForm = useForm<z.infer<typeof NotificationsFormSchema>>({
    resolver: zodResolver(NotificationsFormSchema),
    defaultValues,
  })

  const onSubmit = (values: any) => {
    if (!projectRef) return console.error('Project ref is required')
    updateAuthConfig({ projectRef: projectRef, config: { ...values } })
  }

  useEffect(() => {
    if (authConfig) {
      notificationsForm.reset(defaultValues)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [authConfig])

  return (
    <>
      {isError && (
        <PageSection>
          <PageSectionContent>
            <AlertError error={authConfigError} subject="Failed to retrieve auth configuration" />
          </PageSectionContent>
        </PageSection>
      )}
      {isLoading && (
        <PageSection>
          <PageSectionContent>
            <GenericSkeletonLoader />
          </PageSectionContent>
        </PageSection>
      )}
      {isSuccess && (
        <>
          <PageSection>
            {builtInSMTP && (
              <Admonition
                type="warning"
                title="Set up custom SMTP"
                description={
                  <p>
                    You’re using the built-in email service. This service has rate limits and is not
                    meant to be used for production apps.{' '}
                    <InlineLink
                      href={`${DOCS_URL}/guides/platform/going-into-prod#auth-rate-limits`}
                    >
                      Learn more
                    </InlineLink>{' '}
                  </p>
                }
                layout="horizontal"
                className="mb-4"
                actions={
                  <Button asChild type="default">
                    <Link href={`/project/${projectRef}/auth/smtp`}>Set up SMTP</Link>
                  </Button>
                }
              />
            )}
            <PageSectionMeta>
              <PageSectionSummary>
                <PageSectionTitle>Authentication</PageSectionTitle>
              </PageSectionSummary>
            </PageSectionMeta>
            <PageSectionContent>
              <Card>
                {TEMPLATES_SCHEMAS.filter(
                  (t) => t.misc?.emailTemplateType === 'authentication'
                ).map((template) => {
                  const templateSlug = slugifyTitle(template.title)

                  return (
                    <CardContent key={`${template.id}`} className="p-0">
                      <Link
                        href={`/project/${projectRef}/auth/templates/${templateSlug}`}
                        className="flex items-center justify-between hover:bg-surface-200 transition-colors py-4 px-6 w-full h-full"
                      >
                        <div className="flex flex-col">
                          <h3 className="text-sm text-foreground">{template.title}</h3>
                          {template.purpose && (
                            <p className="text-sm text-foreground-lighter">{template.purpose}</p>
                          )}
                        </div>

                        <div className="flex items-center gap-4">
                          <ChevronRight size={16} className="text-foreground-muted" />
                        </div>
                      </Link>
                    </CardContent>
                  )
                })}
              </Card>
            </PageSectionContent>
          </PageSection>

          <PageSection>
            <PageSectionMeta>
              <PageSectionSummary>
                <PageSectionTitle>Security</PageSectionTitle>
              </PageSectionSummary>
            </PageSectionMeta>
            <PageSectionContent>
              {!acknowledged && (
                <Admonition showIcon={false} type="tip" className="relative mb-6">
                  <Tooltip>
                    <TooltipTrigger
                      onClick={() => setAcknowledged(true)}
                      className="absolute top-3 right-3 opacity-30 hover:opacity-100 transition-opacity"
                    >
                      <X size={14} className="text-foreground-light" />
                    </TooltipTrigger>
                    <TooltipContent side="bottom">Dismiss</TooltipContent>
                  </Tooltip>
                  <div className="flex flex-col md:flex-row md:items-center gap-y-2 md:gap-x-8 justify-between px-2 py-1">
                    <div className="flex flex-col gap-y-0.5">
                      <div className="flex flex-col gap-y-2 items-start">
                        <Badge variant="success" className="-ml-0.5 uppercase">
                          New
                        </Badge>
                        <p className="text-sm font-medium">
                          Notify users about security-sensitive actions on their accounts
                        </p>
                      </div>
                      <p className="text-sm text-foreground-lighter text-balance">
                        We’ve expanded our email templates to handle security-sensitive actions. The
                        list of templates will continue to grow as our feature-set changes, and as
                        we{' '}
                        <InlineLink href="https://github.com/orgs/supabase/discussions/40349">
                          gather feedback
                        </InlineLink>{' '}
                        from our community .
                      </p>
                    </div>
                    <Button
                      asChild
                      type="default"
                      icon={<ExternalLink strokeWidth={1.5} />}
                      className="mt-2"
                    >
                      <Link href={`${DOCS_URL}/guides/auth/auth-email-templates`} target="_blank">
                        Docs
                      </Link>
                    </Button>
                  </div>
                </Admonition>
              )}

              <Form_Shadcn_ {...notificationsForm}>
                <form onSubmit={notificationsForm.handleSubmit(onSubmit)} className="space-y-4">
                  <Card>
                    {TEMPLATES_SCHEMAS.filter((t) => t.misc?.emailTemplateType === 'security').map(
                      (template) => {
                        const templateSlug = slugifyTitle(template.title)
                        const templateEnabledKey =
                          `MAILER_NOTIFICATIONS_${template.id?.replace('_NOTIFICATION', '')}_ENABLED` as keyof typeof authConfig

                        return (
                          <CardContent
                            key={`${template.id}`}
                            className="p-0 flex items-center justify-between hover:bg-surface-200 transition-colors w-full h-full"
                          >
                            <Link
                              href={`/project/${projectRef}/auth/templates/${templateSlug}`}
                              className="flex flex-col flex-1 py-4 px-6"
                            >
                              <h3 className="text-sm text-foreground">{template.title}</h3>
                              {template.purpose && (
                                <p className="text-sm text-foreground-lighter">
                                  {template.purpose}
                                </p>
                              )}
                            </Link>

                            <div className="flex items-center gap-4 h-full pl-2 relative">
                              <FormField_Shadcn_
                                control={notificationsForm.control}
                                name={templateEnabledKey}
                                render={({ field }) => (
                                  <FormControl_Shadcn_>
                                    <Switch
                                      checked={field.value}
                                      onCheckedChange={field.onChange}
                                      disabled={!canUpdateConfig}
                                    />
                                  </FormControl_Shadcn_>
                                )}
                              />

                              <Link
                                href={`/project/${projectRef}/auth/templates/${templateSlug}`}
                                className="py-6 pr-6"
                              >
                                <ChevronRight size={16} className="text-foreground-muted" />
                              </Link>
                            </div>
                          </CardContent>
                        )
                      }
                    )}
                    <CardFooter className="justify-end space-x-2">
                      {notificationsForm.formState.isDirty && (
                        <Button type="default" onClick={() => notificationsForm.reset()}>
                          Cancel
                        </Button>
                      )}
                      <Button
                        type="primary"
                        htmlType="submit"
                        disabled={
                          !canUpdateConfig ||
                          isUpdatingConfig ||
                          !notificationsForm.formState.isDirty
                        }
                        loading={isUpdatingConfig}
                      >
                        Save changes
                      </Button>
                    </CardFooter>
                  </Card>
                </form>
              </Form_Shadcn_>
            </PageSectionContent>
          </PageSection>
        </>
      )}
    </>
  )
}

Subdomains

Frequently Asked Questions

What does EmailTemplates() do?
EmailTemplates() is a function in the supabase codebase.
What does EmailTemplates() call?
EmailTemplates() calls 1 function(s): slugifyTitle.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free