Skip to content

SmtpClient

email_profile.clients.smtp.client.SmtpClient

Low-level SMTP client. Reuse via with for batch sends.

Source code in email_profile/clients/smtp/client.py
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 SmtpClient:
    """Low-level SMTP client. Reuse via ``with`` for batch sends."""

    def __init__(
        self,
        *,
        host: SMTPHost,
        user: str,
        password: str,
    ) -> None:
        self._host = host
        self._user = user
        self._password = password
        self._smtp: Optional[smtplib.SMTP] = None

    @property
    def host(self) -> SMTPHost:
        return self._host

    @property
    def user(self) -> str:
        return self._user

    @property
    def is_connected(self) -> bool:
        return self._smtp is not None

    def connect(self) -> SmtpClient:
        if self._host.ssl:
            smtp: smtplib.SMTP = smtplib.SMTP_SSL(
                self._host.host, self._host.port
            )
        else:
            smtp = smtplib.SMTP(self._host.host, self._host.port)
            if self._host.starttls:
                smtp.starttls()
        smtp.login(self._user, self._password)
        self._smtp = smtp
        return self

    def close(self) -> None:
        if self._smtp is not None:
            try:
                self._smtp.quit()
            finally:
                self._smtp = None

    def send(self, message: EmailMessage) -> None:
        """Send a pre-built message through the current SMTP session."""
        if self._smtp is None:
            raise RuntimeError(
                "SmtpClient is not connected. Use `with` or call connect()."
            )
        send_fn = with_retry()(self._smtp.send_message)
        send_fn(message)

    def __enter__(self) -> SmtpClient:
        return self.connect()

    def __exit__(self, exc_type, exc, tb) -> None:
        self.close()

    def __repr__(self) -> str:
        state = "connected" if self.is_connected else "disconnected"
        return f"SmtpClient(host={self._host.host!r}, user={self._user!r}, {state})"

host property

is_connected property

user property

__enter__()

Source code in email_profile/clients/smtp/client.py
162
163
def __enter__(self) -> SmtpClient:
    return self.connect()

__exit__(exc_type, exc, tb)

Source code in email_profile/clients/smtp/client.py
165
166
def __exit__(self, exc_type, exc, tb) -> None:
    self.close()

__init__(*, host, user, password)

Source code in email_profile/clients/smtp/client.py
109
110
111
112
113
114
115
116
117
118
119
def __init__(
    self,
    *,
    host: SMTPHost,
    user: str,
    password: str,
) -> None:
    self._host = host
    self._user = user
    self._password = password
    self._smtp: Optional[smtplib.SMTP] = None

__repr__()

Source code in email_profile/clients/smtp/client.py
168
169
170
def __repr__(self) -> str:
    state = "connected" if self.is_connected else "disconnected"
    return f"SmtpClient(host={self._host.host!r}, user={self._user!r}, {state})"

close()

Source code in email_profile/clients/smtp/client.py
146
147
148
149
150
151
def close(self) -> None:
    if self._smtp is not None:
        try:
            self._smtp.quit()
        finally:
            self._smtp = None

connect()

Source code in email_profile/clients/smtp/client.py
133
134
135
136
137
138
139
140
141
142
143
144
def connect(self) -> SmtpClient:
    if self._host.ssl:
        smtp: smtplib.SMTP = smtplib.SMTP_SSL(
            self._host.host, self._host.port
        )
    else:
        smtp = smtplib.SMTP(self._host.host, self._host.port)
        if self._host.starttls:
            smtp.starttls()
    smtp.login(self._user, self._password)
    self._smtp = smtp
    return self

send(message)

Send a pre-built message through the current SMTP session.

Source code in email_profile/clients/smtp/client.py
153
154
155
156
157
158
159
160
def send(self, message: EmailMessage) -> None:
    """Send a pre-built message through the current SMTP session."""
    if self._smtp is None:
        raise RuntimeError(
            "SmtpClient is not connected. Use `with` or call connect()."
        )
    send_fn = with_retry()(self._smtp.send_message)
    send_fn(message)