Setting up SMTP with Digital Ocean Setup

I setup Gramps Web through the one-click digital ocean setup and I’ve gotten it running finally. The only problem I noticed is that during the entire setup, there was nowhere to setup my SMTP configuration.

I tried adding environment variables to my google mail account but nothing is happening. This problem comes up when a user wants to create an account but is waiting for the confirmation email, which is never sent.

Danny,

In the DO setup, email configuration should be part of the same form where you create the admin account.

Thanks for the reply David, this isn’t the case for me. During the initial setup, it only asked the admin user name and password and my email. Nothing about SMTP configuration.

Is there a way to configure it after the initial setup? Or must I restart from scratch?

Also, are you aware if Gmail can not be used?

GMail requires OAuthm, so it cannot be used.

You can modify the config by editing environment variables in the docker compose file at /opt/grampsweb.

I’ve set Mailgrid to be used as my SMTP server and input the information as such

GRAMPSWEB_BASE_URL: “https://shiga.ca
GRAMPSWEB_EMAIL_HOST: “smtp.mailgun.org
GRAMPSWEB_EMAIL_PORT: 465
GRAMPSWEB_EMAIL_USE_TLS: True
GRAMPSWEB_EMAIL_HOST_USER: “minatogawafamilytree@gmail.com
GRAMPSWEB_EMAIL_HOST_PASSWORD: “password-inplace”
GRAMPSWEB_DEFAULT_FROM_EMAIL: “minatogawafamilytree@gmail.com

In the grampsweb section of the docker-compose file but I still don’t get any email sent or any error in the logs. @DavidMStraub What log do I look at to see the emailing error?

The Celery log. You can also use the command line (python -m gramps_webapi ...) to send dummy emails for testing. Try setting GRAMPSWEB_EMAIL_USE_TLS: False, it is sometimes needed.

No wait, there is actually an error in your config (and my answer), true and false need to be lowercase, see the Info box just before here: Server configuration - Gramps Web

This is a Flask thing, so don’t blame me.

Thanks @DavidMStraub, I adjusted the configuration and I viewed the celery log and can see that the Connection to SMTP server refused.

Still unsure what setting is incorrect, I’m now using mailgrid for SMTP connection.

1 Like

Hi David,

I took a break because I got frustrated I couldn’t get the SMTP working with mailgun.

Here is the current configuration:

environment: &grampsweb-env
  VIRTUAL_PORT: "5000"
  GRAMPSWEB_TREE: Gramps Web
  GUNICORN_NUM_WORKERS: 3
  GRAMPSWEB_CELERY_CONFIG__broker_url: "redis://grampsweb_redis:6379/0"
  GRAMPSWEB_CELERY_CONFIG__result_backend: "redis://grampsweb_redis:6379/0"
  GRAMPSWEB_RATELIMIT_STORAGE_URI: redis://grampsweb_redis:6379/1
  GRAMPSWEB_BASE_URL: "https://shiga.ca"
  GRAMPSWEB_EMAIL_HOST: "smtp.mailgun.org"
  GRAMPSWEB_EMAIL_PORT: 587
  GRAMPSWEB_EMAIL_USE_TLS: "true"
  GRAMPSWEB_EMAIL_HOST_USER: "admin@shiga.ca"
  GRAMPSWEB_EMAIL_HOST_PASSWORD: "password"
  GRAMPSWEB_DEFAULT_FROM_EMAIL: "admin@shiga.ca"

Any idea what went wrong here? is there a mail client that you recommend?

I realize that the problem might be from my digitalocean droplet where SMTP ports are blocked from 25, 465, 587 - but DigitalOcean has the 1click app for gramps - is this the same experience with others?

Interesting, I wasn’t aware of that.

Update: I was able to get the SMTP feature working with the help of ChatGPT. I used port 2525 with Mailgun but I had to tweak the util.py file. I found that Gramsweb SMTP code was forcing a implicit SSL socket smtplilb.SMTP_SSL for every send and this works great for 465 but my server and Mailgun was using port 2525 which speaks plain SMTP and expects a STARTTLS.

Because the app tried SMTP_SSL against a STARTTLS port it failed with SSL: WRONG_VERSION_NUMBER and similar TLS/auth errors.

To fix it I updated util.py so the app:

-uses smtplib.SMTP() for the connection,

-calls starttls() when EMAIL_USE_TLS is set, and

-only uses implicit SSL (SMTP_SSL) if explicitly configured to do so.

I then built a small custom Docker image that bakes the patched util.py into the Gramps-Web image and redeployed the containers. The fix preserves encryption (STARTTLS is still TLS), and it’s reproducible because it’s included in a built image rather than edited manually inside the container.

For those interested in the for send_email, find it below:

”def send_email(
subject: str,
body: str,
to: Sequence[str],
from_email: str | None = None,
body_html: str | None = None,
) → None:
“”“Send an e-mail message via SMTP with optional STARTTLS.”“”
msg = EmailMessage()
msg.set_content(body)
if body_html:
msg.add_alternative(body_html, subtype=“html”)
msg[“Subject”] = subject
if not from_email:
from_email = get_config(“DEFAULT_FROM_EMAIL”)
msg[“From”] = from_email
msg[“To”] = ", ".join(to)
msg[“Message-ID”] = make_msgid()

host = get_config("EMAIL_HOST")
port = int(get_config("EMAIL_PORT"))
user = get_config("EMAIL_HOST_USER")
password = get_config("EMAIL_HOST_PASSWORD")
use_tls = get_config("EMAIL_USE_TLS")

try:
    smtp = smtplib.SMTP(host=host, port=port, timeout=10)
    smtp.ehlo()

    # Upgrade to TLS if requested (STARTTLS)
    if use_tls:
        smtp.starttls()
        smtp.ehlo()

    if user:
        smtp.login(user, password)

    smtp.send_message(msg)
    smtp.quit()

except ConnectionRefusedError:
    current_app.logger.error("Connection to SMTP server refused.")
    raise ValueError("Connection was refused.")
except socket.timeout:
    current_app.logger.error("SMTP connection attempt timed out.")
    raise ValueError("Connection attempt timed out.")
except OSError as e:
    current_app.logger.error(f"Error while trying to send e-mail: {e}")
    raise ValueError("Error while trying to send e-mail.")"

Then I made sure that this new util.py file is in the same folder as the Dockerfile which has the following code:

FROM http://ghcr.io/gramps-project/grampsweb:latest
COPY util.py /usr/local/lib/python3.11/dist-packages/gramps_webapi/api/util.py

, adjusted the docker-compose file to use this new Dockerfile

“grampsweb:
container_name: grampsweb
build:
context: /opt/grampsweb ( folder of where the new dockerfile is)

container_name: grampsweb_celery
build:
context: /opt/grampsweb
dockerfile: Dockerfile

And rebuild with docker-compose

1 Like