Skip to content

_email

EmailSettings

Bases: BaseSettings

Class with settings for email-sending feature.

Source code in fractal_server/config/_email.py
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
class EmailSettings(BaseSettings):
    """
    Class with settings for email-sending feature.
    """

    model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)

    FRACTAL_EMAIL_SENDER: EmailStr | None = None
    """
    Address of the OAuth-signup email sender.
    """
    FRACTAL_EMAIL_PASSWORD: SecretStr | None = None
    """
    Password for the OAuth-signup email sender.
    """
    FRACTAL_EMAIL_PASSWORD_KEY: SecretStr | None = None
    """
    Key value for `cryptography.fernet` decrypt
    """
    FRACTAL_EMAIL_SMTP_SERVER: str | None = None
    """
    SMTP server for the OAuth-signup emails.
    """
    FRACTAL_EMAIL_SMTP_PORT: int | None = None
    """
    SMTP server port for the OAuth-signup emails.
    """
    FRACTAL_EMAIL_INSTANCE_NAME: str | None = None
    """
    Fractal instance name, to be included in the OAuth-signup emails.
    """
    FRACTAL_EMAIL_RECIPIENTS: str | None = None
    """
    Comma-separated list of recipients of the OAuth-signup emails.
    """
    FRACTAL_EMAIL_USE_STARTTLS: Literal["true", "false"] = "true"
    """
    Whether to use StartTLS when using the SMTP server.
    Accepted values: 'true', 'false'.
    """
    FRACTAL_EMAIL_USE_LOGIN: Literal["true", "false"] = "true"
    """
    Whether to use login when using the SMTP server.
    If 'true', FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KEY must be
    provided.
    Accepted values: 'true', 'false'.
    """

    public: PublicEmailSettings | None = None
    """
    The validated field which is actually used in `fractal-server
    (automatically populated upon creation).
    """

    @model_validator(mode="after")
    def validate_email_settings(self):
        """
        Set `self.public`.
        """

        email_values = [
            self.FRACTAL_EMAIL_SENDER,
            self.FRACTAL_EMAIL_SMTP_SERVER,
            self.FRACTAL_EMAIL_SMTP_PORT,
            self.FRACTAL_EMAIL_INSTANCE_NAME,
            self.FRACTAL_EMAIL_RECIPIENTS,
        ]
        if len(set(email_values)) == 1:
            # All required EMAIL attributes are None
            pass
        elif None in email_values:
            # Not all required EMAIL attributes are set
            error_msg = (
                "Invalid FRACTAL_EMAIL configuration. "
                f"Given values: {email_values}."
            )
            raise ValueError(error_msg)
        else:
            use_starttls = self.FRACTAL_EMAIL_USE_STARTTLS == "true"
            use_login = self.FRACTAL_EMAIL_USE_LOGIN == "true"

            if use_login:
                if self.FRACTAL_EMAIL_PASSWORD is None:
                    raise ValueError(
                        "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
                        "'FRACTAL_EMAIL_PASSWORD' is not provided."
                    )
                if self.FRACTAL_EMAIL_PASSWORD_KEY is None:
                    raise ValueError(
                        "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
                        "'FRACTAL_EMAIL_PASSWORD_KEY' is not provided."
                    )
                try:
                    (
                        Fernet(
                            self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
                        )
                        .decrypt(
                            self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
                        )
                        .decode("utf-8")
                    )
                except Exception as e:
                    raise ValueError(
                        "Invalid pair (FRACTAL_EMAIL_PASSWORD, "
                        "FRACTAL_EMAIL_PASSWORD_KEY). "
                        f"Original error: {str(e)}."
                    )
                password = self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
            else:
                password = None

            if self.FRACTAL_EMAIL_PASSWORD_KEY is not None:
                key = self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
            else:
                key = None

            self.public = PublicEmailSettings(
                sender=self.FRACTAL_EMAIL_SENDER,
                recipients=self.FRACTAL_EMAIL_RECIPIENTS.split(","),
                smtp_server=self.FRACTAL_EMAIL_SMTP_SERVER,
                port=self.FRACTAL_EMAIL_SMTP_PORT,
                encrypted_password=password,
                encryption_key=key,
                instance_name=self.FRACTAL_EMAIL_INSTANCE_NAME,
                use_starttls=use_starttls,
                use_login=use_login,
            )

        return self

FRACTAL_EMAIL_INSTANCE_NAME = None class-attribute instance-attribute

Fractal instance name, to be included in the OAuth-signup emails.

FRACTAL_EMAIL_PASSWORD = None class-attribute instance-attribute

Password for the OAuth-signup email sender.

FRACTAL_EMAIL_PASSWORD_KEY = None class-attribute instance-attribute

Key value for cryptography.fernet decrypt

FRACTAL_EMAIL_RECIPIENTS = None class-attribute instance-attribute

Comma-separated list of recipients of the OAuth-signup emails.

FRACTAL_EMAIL_SENDER = None class-attribute instance-attribute

Address of the OAuth-signup email sender.

FRACTAL_EMAIL_SMTP_PORT = None class-attribute instance-attribute

SMTP server port for the OAuth-signup emails.

FRACTAL_EMAIL_SMTP_SERVER = None class-attribute instance-attribute

SMTP server for the OAuth-signup emails.

FRACTAL_EMAIL_USE_LOGIN = 'true' class-attribute instance-attribute

Whether to use login when using the SMTP server. If 'true', FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KEY must be provided. Accepted values: 'true', 'false'.

FRACTAL_EMAIL_USE_STARTTLS = 'true' class-attribute instance-attribute

Whether to use StartTLS when using the SMTP server. Accepted values: 'true', 'false'.

public = None class-attribute instance-attribute

The validated field which is actually used in `fractal-server (automatically populated upon creation).

validate_email_settings()

Set self.public.

Source code in fractal_server/config/_email.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
@model_validator(mode="after")
def validate_email_settings(self):
    """
    Set `self.public`.
    """

    email_values = [
        self.FRACTAL_EMAIL_SENDER,
        self.FRACTAL_EMAIL_SMTP_SERVER,
        self.FRACTAL_EMAIL_SMTP_PORT,
        self.FRACTAL_EMAIL_INSTANCE_NAME,
        self.FRACTAL_EMAIL_RECIPIENTS,
    ]
    if len(set(email_values)) == 1:
        # All required EMAIL attributes are None
        pass
    elif None in email_values:
        # Not all required EMAIL attributes are set
        error_msg = (
            "Invalid FRACTAL_EMAIL configuration. "
            f"Given values: {email_values}."
        )
        raise ValueError(error_msg)
    else:
        use_starttls = self.FRACTAL_EMAIL_USE_STARTTLS == "true"
        use_login = self.FRACTAL_EMAIL_USE_LOGIN == "true"

        if use_login:
            if self.FRACTAL_EMAIL_PASSWORD is None:
                raise ValueError(
                    "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
                    "'FRACTAL_EMAIL_PASSWORD' is not provided."
                )
            if self.FRACTAL_EMAIL_PASSWORD_KEY is None:
                raise ValueError(
                    "'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
                    "'FRACTAL_EMAIL_PASSWORD_KEY' is not provided."
                )
            try:
                (
                    Fernet(
                        self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
                    )
                    .decrypt(
                        self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
                    )
                    .decode("utf-8")
                )
            except Exception as e:
                raise ValueError(
                    "Invalid pair (FRACTAL_EMAIL_PASSWORD, "
                    "FRACTAL_EMAIL_PASSWORD_KEY). "
                    f"Original error: {str(e)}."
                )
            password = self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
        else:
            password = None

        if self.FRACTAL_EMAIL_PASSWORD_KEY is not None:
            key = self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
        else:
            key = None

        self.public = PublicEmailSettings(
            sender=self.FRACTAL_EMAIL_SENDER,
            recipients=self.FRACTAL_EMAIL_RECIPIENTS.split(","),
            smtp_server=self.FRACTAL_EMAIL_SMTP_SERVER,
            port=self.FRACTAL_EMAIL_SMTP_PORT,
            encrypted_password=password,
            encryption_key=key,
            instance_name=self.FRACTAL_EMAIL_INSTANCE_NAME,
            use_starttls=use_starttls,
            use_login=use_login,
        )

    return self

PublicEmailSettings

Bases: BaseModel

Schema for EmailSettings.public, namely the ready-to-use settings.

Attributes:

Name Type Description
sender EmailStr

Sender email address

recipients list[EmailStr]

List of recipients email address

smtp_server str

SMTP server address

port int

SMTP server port

password int

Sender password

instance_name str

Name of SMTP server instance

use_starttls bool

Whether to use the security protocol

use_login bool

Whether to use login

Source code in fractal_server/config/_email.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class PublicEmailSettings(BaseModel):
    """
    Schema for `EmailSettings.public`, namely the ready-to-use settings.

    Attributes:
        sender: Sender email address
        recipients: List of recipients email address
        smtp_server: SMTP server address
        port: SMTP server port
        password: Sender password
        instance_name: Name of SMTP server instance
        use_starttls: Whether to use the security protocol
        use_login: Whether to use login
    """

    sender: EmailStr
    recipients: list[EmailStr] = Field(min_length=1)
    smtp_server: str
    port: int
    encrypted_password: SecretStr | None = None
    encryption_key: SecretStr | None = None
    instance_name: str
    use_starttls: bool
    use_login: bool