Home / Function/ SmtpForm() — supabase Function Reference

SmtpForm() — supabase Function Reference

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

Entity Profile

Dependency Diagram

graph TD
  1b4f5ba4_56f1_a45b_744d_125c5b3f5a1a["SmtpForm()"]
  374f82f7_5e77_996f_abbe_d2a0be394389["urlRegex()"]
  1b4f5ba4_56f1_a45b_744d_125c5b3f5a1a -->|calls| 374f82f7_5e77_996f_abbe_d2a0be394389
  27132dab_dd90_85af_da0b_aff68953e99c["generateFormValues()"]
  1b4f5ba4_56f1_a45b_744d_125c5b3f5a1a -->|calls| 27132dab_dd90_85af_da0b_aff68953e99c
  9782c537_571a_9c24_d6c8_b1ee414b08a5["isSmtpEnabled()"]
  1b4f5ba4_56f1_a45b_744d_125c5b3f5a1a -->|calls| 9782c537_571a_9c24_d6c8_b1ee414b08a5
  style 1b4f5ba4_56f1_a45b_744d_125c5b3f5a1a fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.tsx lines 46–501

export const SmtpForm = () => {
  const { ref: projectRef } = useParams()
  const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
  const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation()

  const [enableSmtp, setEnableSmtp] = useState(false)
  const [hidden, setHidden] = useState(true)

  const { can: canReadConfig } = useAsyncCheckPermissions(
    PermissionAction.READ,
    'custom_config_gotrue'
  )
  const { can: canUpdateConfig } = useAsyncCheckPermissions(
    PermissionAction.UPDATE,
    'custom_config_gotrue'
  )

  const smtpSchema = yup.object({
    SMTP_ADMIN_EMAIL: yup.string().when('ENABLE_SMTP', {
      is: true,
      then: (schema) =>
        schema.email('Must be a valid email').required('Sender email address is required'),
      otherwise: (schema) => schema,
    }),
    SMTP_SENDER_NAME: yup.string().when('ENABLE_SMTP', {
      is: true,
      then: (schema) => schema.required('Sender name is required'),
      otherwise: (schema) => schema,
    }),
    SMTP_HOST: yup.string().when('ENABLE_SMTP', {
      is: true,
      then: (schema) =>
        schema
          .matches(urlRegex({ excludeSimpleDomains: false }), 'Must be a valid URL or IP address')
          .required('Host URL is required.'),
      otherwise: (schema) => schema,
    }),
    SMTP_PORT: yup.number().when('ENABLE_SMTP', {
      is: true,
      then: (schema) =>
        schema
          .required('Port number is required.')
          .min(1, 'Must be a valid port number more than 0')
          .max(65535, 'Must be a valid port number no more than 65535'),
      otherwise: (schema) => schema,
    }),
    SMTP_MAX_FREQUENCY: yup.number().when('ENABLE_SMTP', {
      is: true,
      then: (schema) =>
        schema
          .required('Rate limit is required.')
          .min(1, 'Must be more than 0')
          .max(32767, 'Must not be more than 32,767 an hour'),
      otherwise: (schema) => schema,
    }),
    SMTP_USER: yup.string().when('ENABLE_SMTP', {
      is: true,
      then: (schema) => schema.required('SMTP Username is required'),
      otherwise: (schema) => schema,
    }),
    SMTP_PASS: yup.string(),
    ENABLE_SMTP: yup.boolean().required(),
  })

  const form = useForm<SmtpFormValues>({
    resolver: yupResolver(smtpSchema),
    defaultValues: {
      SMTP_ADMIN_EMAIL: '',
      SMTP_SENDER_NAME: '',
      SMTP_HOST: '',
      SMTP_PORT: undefined,
      SMTP_MAX_FREQUENCY: undefined,
      SMTP_USER: '',
      SMTP_PASS: '',
      ENABLE_SMTP: false,
    },
  })

  // Update form values when auth config is loaded
  useEffect(() => {
    if (authConfig) {
      const formValues = generateFormValues(authConfig)
      // Convert SMTP_PORT from string to number if it exists
      if (formValues.SMTP_PORT) {
        formValues.SMTP_PORT = Number(formValues.SMTP_PORT) as any
      }
      form.reset({
        ...formValues,
        ENABLE_SMTP: isSmtpEnabled(authConfig),
      } as SmtpFormValues)
      setEnableSmtp(isSmtpEnabled(authConfig))
    }
  }, [authConfig, form])

  // Update enableSmtp state when the form field changes
  useEffect(() => {
    const subscription = form.watch((value, { name }) => {
      if (name === 'ENABLE_SMTP') {
        setEnableSmtp(value.ENABLE_SMTP as boolean)
      }
    })
    return () => subscription.unsubscribe()
  }, [form])

  const onSubmit = (values: SmtpFormValues) => {
    const { ENABLE_SMTP, ...rest } = values
    const basePayload = ENABLE_SMTP ? rest : defaultDisabledSmtpFormValues

    // When enabling SMTP, set RATE_LIMIT_EMAIL_SENT to 30
    // When disabling, backend will handle resetting to default
    const isEnablingSmtp = ENABLE_SMTP && !isSmtpEnabled(authConfig)
    const payload = {
      ...basePayload,
      ...(isEnablingSmtp && { RATE_LIMIT_EMAIL_SENT: 30 }),
    }

    // Format payload: Convert port to string
    if (payload.SMTP_PORT) {
      payload.SMTP_PORT = payload.SMTP_PORT.toString() as any
    }

    // the SMTP_PASS is write-only, it's never shown. If we don't delete it from the payload, it will replace the
    // previously saved value with an empty one
    if (payload.SMTP_PASS === '') {
      delete payload.SMTP_PASS
    }

    updateAuthConfig(
      { projectRef: projectRef!, config: payload as any },
      {
        onError: (error) => {
          toast.error(`Failed to update settings: ${error.message}`)
        },
        onSuccess: () => {
          setHidden(true)
          toast.success('Successfully updated settings')
        },
      }
    )
  }

  if (isError) {
    return (
      <PageSection>
        <PageSectionContent>
          <AlertError error={authConfigError} subject="Failed to retrieve auth configuration" />
        </PageSectionContent>
      </PageSection>
    )
  }

  if (!canReadConfig) {
    return (
      <PageSection>
        <PageSectionContent>
          <NoPermission resourceText="view SMTP settings" />
        </PageSectionContent>
      </PageSection>
    )
  }

  return (
    <PageSection>
      <PageSectionContent>
        <Form_Shadcn_ {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)}>
            <Card>
              <CardContent>
                <FormField_Shadcn_
                  control={form.control}
                  name="ENABLE_SMTP"
                  render={({ field }) => (
                    <FormItemLayout
                      layout="flex-row-reverse"
                      label="Enable custom SMTP"
                      description={
                        <p className="max-w-full prose text-sm text-foreground-lighter">
                          Emails will be sent using your custom SMTP provider. Email rate limits can
                          be adjusted{' '}
                          <InlineLink href={`/project/${projectRef}/auth/rate-limits`}>
                            here
                          </InlineLink>
                          .
                        </p>
                      }
                    >
                      <FormControl_Shadcn_>
                        <Switch
                          checked={field.value}
                          onCheckedChange={field.onChange}
                          disabled={!canUpdateConfig}
                        />
                      </FormControl_Shadcn_>
                    </FormItemLayout>
                  )}
                />

                {enableSmtp && !isSmtpEnabled(form.getValues() as any) && (
                  <Admonition
                    type="warning"
                    title="All fields must be filled"
                    description="Each of the fields below must be filled before custom SMTP can be enabled."
                    className="bg-warning-200 border-warning-400 mt-4"
                  />
                )}
              </CardContent>

              {enableSmtp && (
                <>
                  <CardContent className="py-6">
                    <div className="grid grid-cols-12 gap-6">
                      <div className="col-span-4">
                        <h3 className="text-sm mb-1">Sender details</h3>
                        <p className="text-sm text-foreground-lighter text-balance">
                          Configure the sender information for your emails.
                        </p>
                      </div>
                      <div className="col-span-8 space-y-4">
                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_ADMIN_EMAIL"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Sender email address"
                              description="The email address the emails are sent from."
                            >
                              <FormControl_Shadcn_>
                                <Input_Shadcn_
                                  {...field}
                                  placeholder="noreply@yourdomain.com"
                                  disabled={!canUpdateConfig}
                                />
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />

                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_SENDER_NAME"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Sender name"
                              description="Name displayed in the recipient's inbox."
                            >
                              <FormControl_Shadcn_>
                                <Input_Shadcn_
                                  {...field}
                                  placeholder="Your Name"
                                  disabled={!canUpdateConfig}
                                />
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />
                      </div>
                    </div>
                  </CardContent>

                  <CardContent className="py-6">
                    <div className="grid grid-cols-12 gap-6">
                      <div className="col-span-4">
                        <h3 className="text-sm mb-1">SMTP provider settings</h3>
                        <p className="text-sm text-foreground-lighter text-balance">
                          Your SMTP credentials will always be encrypted in our database.
                        </p>
                      </div>
                      <div className="col-span-8 space-y-4">
                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_HOST"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Host"
                              description="Hostname or IP address of your SMTP server."
                            >
                              <FormControl_Shadcn_>
                                <Input_Shadcn_
                                  {...field}
                                  placeholder="your.smtp.host.com"
                                  disabled={!canUpdateConfig}
                                />
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />

                        {form.watch('SMTP_HOST')?.endsWith('.gmail.com') && (
                          <Admonition
                            type="warning"
                            title="Check your SMTP provider"
                            description="It looks like the SMTP provider you entered is designed
                            for sending personal rather than transactional email messages. Email deliverability may
                            be impacted."
                            className="mb-4 bg-warning-200 border-warning-400"
                          />
                        )}

                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_PORT"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Port number"
                              description={
                                <>
                                  <span className="block">
                                    Port used by your SMTP server. Common ports include 465 and 587.
                                    Avoid using port 25 as it is often blocked by providers to curb
                                    spam.
                                  </span>
                                </>
                              }
                            >
                              <FormControl_Shadcn_>
                                <Input_Shadcn_
                                  type="number"
                                  value={field.value}
                                  onChange={(e) => field.onChange(Number(e.target.value))}
                                  placeholder="587"
                                  disabled={!canUpdateConfig}
                                />
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />

                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_MAX_FREQUENCY"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Minimum interval per user"
                              description="The minimum time in seconds between emails before another email can be sent to the same user."
                            >
                              <FormControl_Shadcn_>
                                <PrePostTab postTab="seconds">
                                  <Input_Shadcn_
                                    type="number"
                                    value={field.value}
                                    onChange={(e) => field.onChange(Number(e.target.value))}
                                    disabled={!canUpdateConfig}
                                  />
                                </PrePostTab>
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />

                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_USER"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Username"
                              description="Username for your SMTP server."
                            >
                              <FormControl_Shadcn_>
                                <Input_Shadcn_
                                  {...field}
                                  placeholder="SMTP Username"
                                  disabled={!canUpdateConfig}
                                />
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />

                        <FormField_Shadcn_
                          control={form.control}
                          name="SMTP_PASS"
                          render={({ field }) => (
                            <FormItemLayout
                              label="Password"
                              description="Password for your SMTP server. For security reasons, this password cannot be viewed once saved."
                            >
                              <FormControl_Shadcn_>
                                <PrePostTab
                                  postTab={
                                    <Button
                                      type="text"
                                      className="p-0"
                                      onClick={() => setHidden(!hidden)}
                                      icon={hidden ? <Eye /> : <EyeOff />}
                                    />
                                  }
                                >
                                  <Input_Shadcn_
                                    {...field}
                                    type={hidden ? 'password' : 'text'}
                                    placeholder={
                                      authConfig?.SMTP_PASS === null ? 'SMTP Password' : '••••••••'
                                    }
                                    disabled={!canUpdateConfig}
                                  />
                                </PrePostTab>
                              </FormControl_Shadcn_>
                            </FormItemLayout>
                          )}
                        />
                      </div>
                    </div>
                  </CardContent>
                </>
              )}

              <CardFooter
                className={cn(
                  form.formState.isDirty ? 'justify-between' : 'justify-end',
                  'gap-x-2'
                )}
              >
                {form.formState.isDirty && (
                  <p className="text-sm text-foreground-light">
                    {enableSmtp ? (
                      <>
                        Rate limit for sending emails will be increased to 30 and{' '}
                        <InlineLink href={`/project/${projectRef}/auth/rate-limits`}>
                          can be adjusted
                        </InlineLink>{' '}
                        after enabling custom SMTP
                      </>
                    ) : (
                      'Rate limit for sending emails will be reduced to 2 after disabling custom SMTP'
                    )}
                  </p>
                )}
                <div className="flex items-center gap-x-2">
                  {form.formState.isDirty && (
                    <Button
                      type="default"
                      onClick={() => {
                        form.reset()
                        setEnableSmtp(isSmtpEnabled(authConfig))
                      }}
                    >
                      Cancel
                    </Button>
                  )}
                  <Button
                    type="primary"
                    htmlType="submit"
                    loading={isUpdatingConfig}
                    disabled={!canUpdateConfig || !form.formState.isDirty}
                  >
                    Save changes
                  </Button>
                </div>
              </CardFooter>
            </Card>
          </form>
        </Form_Shadcn_>
      </PageSectionContent>
    </PageSection>
  )
}

Subdomains

Frequently Asked Questions

What does SmtpForm() do?
SmtpForm() is a function in the supabase codebase.
What does SmtpForm() call?
SmtpForm() calls 3 function(s): generateFormValues, isSmtpEnabled, urlRegex.

Analyze Your Own Codebase

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

Try Supermodel Free