Send test email
curl --request POST \ --url http://localhost:9090/api/v1/admin/settings/email/send-test \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \Send a short message to to through the stored SMTP settings, the stored password
included, to check what a save’s connection does not: the encryption, the certificate,
the credentials and the sender. Answers 200 once the SMTP server has accepted the
message.
The send waits up to 10 seconds to connect, including the TLS handshake for SSL/TLS, and up to 30 seconds for the rest of the conversation.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Example generated
{}Responses
Section titled “Responses”Test email sent
object
Example generated
{ "success": true}Error_code is SMTP_NOT_ENABLED while SMTP is disabled, INVALID_REQUEST_BODY for a
body that will not parse, VALIDATION_ERROR when to is missing,
validator.email.invalid_format when it is not an email address, and SEND_FAILED when
the send fails.
A SEND_FAILED answers one of these fixed messages, chosen by what failed:
- “Unable to send the test email: host name not found.” Check the host name, as for a save.
- “Unable to send the test email: connection timed out.” Check the port and any firewall, as for a save. A server that accepted the connection and then went quiet also ends here, which is what STARTTLS or None against an SSL/TLS port such as 465 looks like.
- “Unable to send the test email: connection refused.” Check the port.
- “The SMTP server did not offer STARTTLS; set the encryption to None only if the server has no TLS.” The encryption is STARTTLS and the server does not offer it. Goiabada does not continue unencrypted.
- “The SMTP server would receive the password unencrypted; set the encryption to STARTTLS or SSL/TLS.”
The encryption is None, a username is set, and the server would be sent the
password in the clear by PLAIN or LOGIN. Only a server on
localhost,127.0.0.1or::1is exempt. - “SMTP credentials are configured but the server offers no authentication.” A username is set and the server offers no AUTH: the wrong host or port, or a server that offers authentication only after STARTTLS, reached with the encryption set to None.
- “The SMTP server offers none of PLAIN, LOGIN or CRAM-MD5.” The server offers only mechanisms Goiabada does not implement, such as XOAUTH2: use a password the server accepts through one of these three, often called an app password or an SMTP key.
- “The TLS connection failed; check the encryption setting and the server’s certificate.”
SSL/TLS against a port that expects STARTTLS, such as 587; a certificate the auth
server does not trust, that has expired, or that names a host other than
smtpHost; or a server that refused the STARTTLS command. Certificates are always verified. - “The SMTP server rejected the username or password.” Check the username and password.
- “The SMTP server refused the message.” The server refused the sender, the
recipient or the message itself, most often because the account may not send
from
smtpFromEmail. - “Unable to send the test email.” Any other failure: a connection that dropped
partway through the conversation, a network the auth server has no route to,
or a stored password the auth server cannot decrypt, such as one encrypted under
a
GOIABADA_AES_ENCRYPTION_KEYit no longer has.
Nothing from the error itself is answered, no address, operating-system error or server reply; the full error goes to the auth server’s log, at Warn, as “unable to send the test email” under the request’s request_id.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Missing or invalid bearer token
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Bearer challenge on token refusals. An operation may also return a handler-level 401 without this header.
The token is valid but does not authorise this request. Four checks answer here, and a caller distinguishes them by error_code.
INSUFFICIENT_SCOPE comes from the route’s authorisation middleware,
before the handler runs: an Admin operation needs one of the scopes
its route names, and an Account operation needs
authserver:manage-account.
USER_CONTEXT_REQUIRED comes from the same middleware on the Account operations, which also require the token to have been issued for a user: one obtained through the client credentials grant carries no auth_time claim and is refused here.
FORBIDDEN comes from the handler, on the account endpoints that resolve a resource by id and then check it belongs to the caller, so a valid token for the wrong user reaches this rather than a 404.
MANAGE_SCOPE_REQUIRED comes from the handler, on the Admin operations
the administrative policy guards. Only authserver:manage creates an
administrator, changes one, or changes what reaches one, so no
granular scope will ever be enough: the remedy is a token holding
authserver:manage, not requesting the route’s scope as for
INSUFFICIENT_SCOPE. An administrator is a user, group or client
holding any of the six administrative permissions (manage,
admin-read, manage-users, manage-clients, manage-settings,
browser-sessions), a user directly or through any of its groups,
the admin console’s own client whatever it holds, and a client
allowed to request the administrative scopes. A granular scope is
refused here when it:
- grants or revokes an administrative permission, directly or by moving a user into or out of a group that holds one, or deletes such a group;
- writes to an administrator user (profile, credentials, enabled, sessions, consents, attributes, memberships, permissions, deletion), an administrative group (settings, attributes, members, permissions, deletion), or an administrator client (settings, authentication, flows, redirect URIs, web origins, token settings, permissions, logo, deletion);
- switches whether a client may request the administrative scopes, on or off, on any client;
- reads an administrator client’s secret;
- changes the email or the audit-log settings;
- changes an administrative permission’s description.
Granular scopes still read administrators. The refusal is answered
after the request’s 400 and 404, writes nothing, carries
WWW-Authenticate: Bearer realm="goiabada", error="insufficient_scope", error_description="...", scope="authserver:manage", and leaves anadministrator_change_refusedaudit record.
Every operation this document secures declares a 403. The public
client logo endpoint, which carries security: [] and authorises
nothing, is the one that does not.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Bearer challenge on scope and administrative-policy refusals; other forbidden responses omit it.
The request failed inside the server, most often a storage error. error_code is INTERNAL_SERVER_ERROR: no detail about the failure, only the request id an operator can find the log line by, and retrying is reasonable. Key rotation’s 500 also answers KEY_SET_INCOMPLETE, which names its cause and no retry clears.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}