# ./discourse-setup plaatst SMTP-gebruikersnaam aan het begin van SMTP-wachtwoord

**URL:** https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710
**Category:** Support
**Tags:** install
**Created:** [5 september 2025 om 12:37 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710 "2025-09-05T12:37:46Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [5 september 2025 om 12:37 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/1 "2025-09-05T12:37:46Z")

</div>

Environment

- Discourse: latest tests-passed
- Host OS: [Ubuntu 24.04 LTS / 24.04.3 LTS]
- Install method: official Docker install, running `./discourse-setup`
- Platform: VPS (Digital Ocean)

Steps to reproduce

1. Run ./discourse-setup from /var/discourse
2. Enter SMTP details when prompted:

- SMTP server: [smtp.example.com](http://smtp.example.com)
- SMTP port: 2525
- SMTP username: [user@example.com](mailto:user@example.com)
- SMTP password: p@ssw0rd!

1. Finish setup and inspect containers/app.yml

Expected result

app.yml should contain two distinct fields, for example:

```plaintext
DISCOURSE_SMTP_USER_NAME: "user@example.com"
DISCOURSE_SMTP_PASSWORD: "p@ssw0rd!"

```

Actual result

The password field is written with the username prepended:

```plaintext
DISCOURSE_SMTP_USER_NAME: "user@example.com"
DISCOURSE_SMTP_PASSWORD: "user@brevo.comp@ssw0rd!"

```

This causes mail delivery to fail, and discourse-doctor confirms the mangled password.

Notes  
• Quoting the password explicitly at the prompt does not change the outcome.  
• Password contains special characters (@, !), but the problem is not just YAML quoting: the username string is literally concatenated at the start of the password.  
• Reproducible across multiple runs of ./discourse-setup.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [15 september 2025 om 01:51 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/2 "2025-09-15T01:51:39Z")

</div>

kun je testen of dit verband houdt met bepaalde tekens in het wachtwoord, zoals @ / ! en of dit de bug aan het licht brengt?

Alle sed/awk en fancy bash scripting in discourse-setup maken het nogal lastig te onderhouden. Misschien heeft @pfaffman hier ideeën over?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 09:56 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/3 "2025-09-15T09:56:20Z")

</div>

Oké. Dat is een goede gok.

@Ethsim2 als je het wachtwoord verandert in iets met alleen cijfers en letters en niet hetzelfde als een deel van de gebruikersnaam, heb je dan dit probleem?

Kun je de waarden delen die je gebruikt?

Ik zal er later vandaag naar kijken.

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 10:15 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/4 "2025-09-15T10:15:57Z")

</div>

> [@pfaffman](#):
>
> Can you share the values you are using?

 ![image](https://global.discourse-cdn.com/meta/original/4X/2/2/8/228ffd817edfd5df21e37b278f74f164de10bdb5.jpeg)

---

<div class="post-metadata">

### Author: ![NateDhaliwal](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/natedhaliwal/32/313494_2.png) [@NateDhaliwal](https://meta.discourse.org/u/NateDhaliwal)
#### Post date: [15 september 2025 om 11:20 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/5 "2025-09-15T11:20:54Z")

</div>

Als je het 83f…com-gedeelte van het wachtwoord zou verwijderen en alleen het wachtwoord (5AH…) zou laten staan, werkt het dan?

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 11:37 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/6 "2025-09-15T11:37:43Z")

</div>

ja, dan voer ik `.\launcher rebuild app` uit, aangezien `.\discourse-setup` SWAP al had geconfigureerd

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 18:26 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/7 "2025-09-15T18:26:28Z")

</div>

> [@Ethsim2](#):
>
> Password contains special characters (@, !), but the problem is not just YAML quoting: the username string is literally concatenated at the start of the password.

Yeah. That’s the issue. There are multiple levels of escaping that need to happen, like when `bash` reads the value, when bash hands the value to `sed`, when `sed` replaces it, and then, maybe, when the yml file gets it. It’s a known issue:

> [@Troubleshoot email on a new Discourse install](https://meta.discourse.org/t/troubleshoot-email-on-a-new-discourse-install/16326/1):
>
> The simplest way is to run `./discourse-setup` again. Did you enter everything correctly? But wait! If your password has anything other than numbers and letters, you might be better off editing your `app.yml` with `nano` or your favorite editor.

I recategorized this as #Support.

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 18:56 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/8 "2025-09-15T18:56:15Z")

</div>

> [@Ethsim2](#):
>
> @

SMTP usernames always contain `@` though, don’t they?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 18:57 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/9 "2025-09-15T18:57:16Z")

</div>

Ja. Ik denk niet dat `@` een probleem zou moeten veroorzaken.

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 18:58 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/10 "2025-09-15T18:58:25Z")

</div>

er staat geen `!` in mijn screenshot waar de concatenatie plaatsvindt

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 19:00 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/11 "2025-09-15T19:00:19Z")

</div>

Wat is het wachtwoord dat u probeert in te voeren?

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 19:21 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/12 "2025-09-15T19:21:53Z")

</div>

> [@pfaffman](#):
>
> What is the password you were trying to enter?

the password on the screenshot is `5AHQXrf4LDUmRB1J` 🙂

Edit: this password is a default Brevo password created on an account that was since deleted

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 19:29 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/13 "2025-09-15T19:29:24Z")

</div>

Ik kan het niet reproduceren. Welk besturingssysteem gebruik je?

```plaintext
root@bro:/var/discourse# ./discourse-setup --skip-connection-test --skip-rebuild
skipping connection test
'samples/standalone.yml' -> 'containers/app.yml'
Found 29GB of memory and 32 physical CPU cores
setting db_shared_buffers = 4096MB
setting UNICORN_WORKERS = 8
containers/app.yml memory parameters updated.

Hostname for your Discourse? [discourse.example.com]: forum.phsics.site

Setting EC to 2
Skipping port check.
Email address for admin account(s)? [me@example.com,you@example.com]: jay@literatecomputing.com
SMTP server address? [smtp.example.com]: smtp-relay.brevo.com
SMTP port? [587]: 2525
SMTP user name? [user@example.com]: 83fca0012@smtp-brevo.com
SMTP password? []: 5AHQXrf4LDUmRB1J
notification email address? [noreply@forum.phsics.site]:
Optional email address for Let's Encrypt warnings? (ENTER to skip) [me@example.com]:
Optional MaxMind Account ID (ENTER to continue without MAXMIND GeoLite2 geolocation database) [123456]:

Does this look right?

Hostname : forum.phsics.site
Email : jay@literatecomputing.com
SMTP address : smtp-relay.brevo.com
SMTP port : 2525
SMTP username : 83fca0012@smtp-brevo.com
SMTP password : 5AHQXrf4LDUmRB1J
Notification email: noreply@forum.phsics.site
MaxMind account ID: (unset)
MaxMind license key: (unset)

ENTER to continue, 'n' to try again, Ctrl+C to exit:
letsencrypt.ssl.template.yml enabled

Configuration file at containers/app.yml updated successfully!

Updates successful. --skip-rebuild requested. Exiting.
root@bro:/var/discourse# grep SMTP containers/app.yml
  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS is required
  # WARNING: SMTP password should be wrapped in quotes to avoid problems
  DISCOURSE_SMTP_ADDRESS: smtp-relay.brevo.com
  DISCOURSE_SMTP_PORT: 2525
  DISCOURSE_SMTP_USER_NAME: 83fca0012@smtp-brevo.com
  DISCOURSE_SMTP_PASSWORD: "5AHQXrf4LDUmRB1J"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true # (optional, default: true)
  DISCOURSE_SMTP_DOMAIN: discourse.example.com # (required by some providers)
  #DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: peer # (optional, default: peer, valid values: none, peer, client_once, fail_if_no_peer_cert)
  #DISCOURSE_SMTP_AUTHENTICATION: plain # (default: plain, valid values: plain, login, cram_md5)

```

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 19:37 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/14 "2025-09-15T19:37:34Z")

</div>

Digital Ocean Ubuntu 24.04

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 19:42 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/15 "2025-09-15T19:42:00Z")

</div>

> **LLM/AI -gegenereerde aanbevelingen**
>
> \nhieronder staat een strakke patch die:\n\n- stopt met het gebruik van sed\n- construeert een percent-gecodeerde SMTP\_URL\n- bewerkt containers/app.yml via Ruby’s YAML (Psych), zodat YAML-quoting/escaping wordt afgehandeld door een echte parser\n- verwijdert de per-sleutel SMTP-variabelen om tegenstrijdigheden te voorkomen\n\n toepassen met `git apply -p0` in de discourse\_docker repo.\n\n- - -\n\nPatch 1 -\n\n`discourse-setup`\n\n(schrijf SMTP met Ruby YAML, niet met sed)\n\n`diff\n--- a/discourse-setup\n+++ b/discourse-setup\n@@ -867,6 +867,77 @@ write_smtp_settings() {\n local app_yml=\"containers/app.yml\"\n [[-f \"$app_yml\"]] || die \"Cannot find $app_yml. Did you run bootstrap?\"\n\n+ # Bouw een URL-gecodeerde SMTP_URL met Python stdlib (geen shell escaping games)\n+ urlencode() {\n+ python3 - \u003c\u003c'PY'\n+import sys, urllib.parse\n+print(urllib.parse.quote(sys.stdin.read().strip(), safe='._~-'))\n+PY\n+ }\n+\n+ # BELANGRIJK: lees variabelen zonder backslash-vervorming\n+ # (deze komen van eerdere prompts; zorg ervoor dat -r wordt gebruikt bij het prompten)\n+ local addr=\"$smtp_address\"\n+ local port=\"$smtp_port\"\n+ local user_enc pass_enc\n+ user_enc=\"$(printf '%s' \"$smtp_user\" | urlencode)\"\n+ pass_enc=\"$(printf '%s' \"$smtp_password\" | urlencode)\"\n+ local smtp_url=\"smtp://${user_enc}:${pass_enc}@${addr}:${port}\"\n+\n+ # Gebruik Ruby om veilig YAML te laden/bewerken/dumpen (doodt 3 lagen van escaping)\n+ ruby - \u003c\u003c'RUBY' \"$app_yml\" \"$smtp_url\"\n+require \"yaml\"\n+require \"psych\"\n+path, url = ARGV\n+doc = YAML.safe_load(File.read(path), permitted_classes: [], aliases: true) || {}\n+\n+# Zorg ervoor dat de top-level structuur een Hash is en env heeft\n+unless doc.is_a?(Hash)\n+ abort \"containers/app.yml parseert niet naar een Hash\"\n+end\n+doc[\"env\"] ||= {}\n+env = doc[\"env\"]\n+\n+# Schrijf enkele regel SMTP_URL; verwijder per-sleutel variabelen om conflicten te voorkomen\n+env[\"SMTP_URL\"] = url\n+%w[DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_PORT DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD].each { |k| env.delete(k) }\n+\n+# Dump terug. (Psych behoudt strings veilig geciteerd zoals nodig.)\n+File.write(path, Psych.dump(doc))\n+RUBY\n+\n+ # snelle sanity check voor de klassieke "wachtwoord voorafgegaan door gebruikersnaam" mislukking\n+ python3 - \u003c\u003c'PY'\n+import re, sys\n+y = open(\"containers/app.yml\",\"r\",encoding=\"utf-8\").read()\n+m = re.search(r'^\\s*SMTP_URL:\\s*(?:\"|\\')?([^\\r\\n\"\\']+)', y, re.M)\n+assert m, \"SMTP_URL ontbreekt na schrijven\"\n+creds = m.group(1).split('@',1)[0].split('://',1)[-1]\n+assert \":\" in creds, \"SMTP_URL creds missen ':'\"\n+u, p = creds.split(':',1)\n+assert not p.startswith(u), \"Wachtwoord lijkt voorafgegaan door gebruikersnaam\"\n+print(\"SMTP_URL ziet er gezond uit.\")\n+PY\n+}\n+\n- # Schrijf per-sleutel SMTP-invoer (adres/poort/gebruikersnaam/wachtwoord)\n- # (legacy: uitgevoerd via sed-substituties)\n- # OPMERKING: historisch fragiel met speciale tekens\n- update_setting_yaml \"DISCOURSE_SMTP_ADDRESS\" \"$smtp_address\"\n- update_setting_yaml \"DISCOURSE_SMTP_PORT\" \"$smtp_port\"\n- update_setting_yaml \"DISCOURSE_SMTP_USER_NAME\" \"$smtp_user\"\n- update_setting_yaml \"DISCOURSE_SMTP_PASSWORD\" \"$smtp_password\"\n-}\n+ # (legacy per-sleutel schrijfacties verwijderd ten gunste van SMTP_URL via YAML)\n+}\n`\n\ndan Patch 2 -\n\n`templates/web.template.yml`\n\n(om het veiligere pad te documenteren)\n\n`diff\n--- a/templates/web.template.yml\n+++ b/templates/web.template.yml\n@@ -68,6 +68,14 @@ params:\n DISCOURSE_SMTP_ENABLE_START_TLS: true\n #DISCOURSE_NOTIFICATION_EMAIL: noreply@example.com\n\n+ ## Voorkeurs SMTP-configuratie in één regel (ingesteld door discourse-setup):\n+ ## URL-codeer gebruikersnaam en wachtwoord; voorbeeld:\n+ ## SMTP_URL: \"smtp://user%40example.com:p%40ss%3Aword@smtp.example.com:587\"\n+ ##\n+ #SMTP_URL:\n+\n ## Als u SMTP_URL niet kunt gebruiken, kunt u in plaats daarvan per-sleutel variabelen instellen.\n ## Pas op dat het bewerken van die regels met shell-tools fragiel kan zijn als waarden\n ## tekens bevatten zoals @, :, /, \", \\, of nieuwe regels.\n`\n\nwaarom dit werkt (en wat het vermijdt)\n\t•\tbash-laag: we interpoleren alleen eenvoudige variabelen; geheimen worden via stdin/argv aan Python/Ruby doorgegeven, niet via sed-regexes of shell-evaluaties.\n\t•\tsed-laag: volledig verwijderd.\n\t•\tYAML-laag: Ruby/Psych behandelt quoting en escaping correct; geen handmatig gemaakte quoting.\n\t•\tSMTP-credentials: %-encoding in SMTP\_URL is de juiste plaats om speciale tekens voor authenticatie te coderen.\n\nals u de voorkeur geeft aan het behouden van per-sleutel variabelen, kan ik u een zusterpatch geven die dezelfde Ruby-YAML-aanpak gebruikt om DISCOURSE\_SMTP\_\* direct in te stellen (nog steeds geen sed), maar de SMTP\_URL-route is de schoonste omdat het één sleutel, één schrijfactie, één coderingstap is.\n

---

<div class="post-metadata">

### Author: ![featheredtoast](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/featheredtoast/32/116994_2.png) [@featheredtoast](https://meta.discourse.org/u/featheredtoast)
#### Post date: [15 september 2025 om 19:46 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/16 "2025-09-15T19:46:44Z")

</div>

We kunnen er helaas niet op vertrouwen dat Ruby is geïnstalleerd op het hostsysteem in discourse-installaties - het zou relatief eenvoudig zijn om het hele script een ruby-script te laten zijn als we dat konden, maar er is geen garantie.

---

<div class="post-metadata">

### Author: ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)
#### Post date: [15 september 2025 om 19:50 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/17 "2025-09-15T19:50:18Z")

</div>

> **also LLM/AI generated**
>
> Got it — no Ruby/Python on the host. Here’s a pure Bash + awk patch that:  
> • builds a percent-encoded SMTP\_URL using only Bash (byte-wise loop; no Python),  
> • inserts or replaces SMTP\_URL under the env: block using awk (no sed),  
> • removes the per-key DISCOURSE\_SMTP\_\* lines (safe anchored deletes),  
> • adds a tiny sanity check using grep/awk only.
> 
> Apply with `git apply -p0` in the discourse\_docker repo.
> 
> ```diff
> --- a/discourse-setup
> +++ b/discourse-setup
> @@ -867,6 +867,130 @@ write_smtp_settings() {
> local app_yml="containers/app.yml"
> [[-f "$app_yml"]] || die "Cannot find $app_yml. Did you run bootstrap?"
> 
> + ##############################################
> + # Pure-Bash URL encoder for SMTP credentials #
> + ##############################################
> + # Encodes everything except A-Z a-z 0-9 . _ ~ -
> + # Works byte-by-byte; requires bash and printf.
> + urlencode_cred() {
> + local s="$1" out= i ch o
> + # set C locale to get byte semantics
> + LC_ALL=C
> + for ((i=0; i<${#s}; i++)); do
> + ch="${s:i:1}"
> + case "$ch" in
> + [A-Za-z0-9._~-])
> + out+="$ch"
> + ;;
> + *)
> + # Get byte value: print char, read with od, then format %HH
> + # Avoid external heavy deps; od is in coreutils / busybox.
> + o=$(printf '%s' "$ch" | od -An -tu1 | awk '{$1=$1;print $1}')
> + # If od somehow failed (empty), fall back to hex via printf %02X of first byte
> + if [-z "$o"]; then
> + o=$(printf '%s' "$ch" | head -c1 | od -An -tu1 | awk '{$1=$1;print $1}')
> + fi
> + printf -v o '%%%02X' "$o"
> + out+="$o"
> + ;;
> + esac
> + done
> + printf '%s' "$out"
> + }
> +
> + # Build SMTP_URL (single line) from collected answers
> + # These vars are gathered earlier in discourse-setup:
> + # $smtp_address $smtp_port $smtp_user $smtp_password
> + local addr="$smtp_address"
> + local port="$smtp_port"
> + local user_enc pass_enc
> + user_enc="$(urlencode_cred "$smtp_user")"
> + pass_enc="$(urlencode_cred "$smtp_password")"
> + local smtp_url="smtp://${user_enc}:${pass_enc}@${addr}:${port}"
> +
> + ########################################################
> + # YAML-safe edit via awk (no sed / no external runtimes)
> + # - ensure env: exists
> + # - insert or replace SMTP_URL under env:
> + # - remove DISCOURSE_SMTP_* keys
> + ########################################################
> + awk -v NEWVAL="$smtp_url" '
> + BEGIN{
> + have_env=0; in_env=0; inserted=0
> + }
> + # detect env: line at top level (start of line, possibly indented 0..)
> + # we’ll consider two-space indentation for children.
> + /^[[:space:]]*env:[[:space:]]*$/ {
> + print; have_env=1; in_env=1; next
> + }
> + # leaving env: block when indentation returns to 0 or next top-level key
> + in_env && /^[^[:space:]]/ {
> + if (!inserted) {
> + print " SMTP_URL: \"" NEWVAL "\""
> + inserted=1
> + }
> + in_env=0
> + }
> + # while in env:, handle replacements and deletions
> + in_env {
> + # drop per-key DISCOURSE_SMTP_* lines entirely
> + if ($0 ~ /^[[:space:]]*DISCOURSE_SMTP_(ADDRESS|PORT|USER_NAME|PASSWORD):/) next
> + # replace existing SMTP_URL line
> + if ($0 ~ /^[[:space:]]*SMTP_URL:[[:space:]]*/) {
> + print " SMTP_URL: \"" NEWVAL "\""
> + inserted=1
> + next
> + }
> + print
> + next
> + }
> + { print }
> + END{
> + # If env: never existed, append it with the key
> + if (!have_env) {
> + print ""
> + print "env:"
> + print " SMTP_URL: \"" NEWVAL "\""
> + } else if (in_env && !inserted) {
> + # env: existed and we were still in it at EOF
> + print " SMTP_URL: \"" NEWVAL "\""
> + }
> + }
> + ' "$app_yml" > "$app_yml.tmp.$$" && mv "$app_yml.tmp.$$" "$app_yml"
> +
> + ##############################################
> + # Sanity check: basic guard against mangling #
> + ##############################################
> + # 1) SMTP_URL present
> + grep -q '^[[:space:]]*SMTP_URL:' "$app_yml" || die "SMTP_URL not written to $app_yml"
> + # 2) password not prefixed by username (classic failure signature)
> + awk '
> + BEGIN{ok=1}
> + /^[[:space:]]*SMTP_URL:[[:space:]]*"/{
> + line=$0
> + gsub(/^[[:space:]]*SMTP_URL:[[:space:]]*"/,"",line)
> + gsub(/".*$/,"",line)
> + # Extract creds before @ and after scheme
> + # e.g. smtp://user:pass@host:port
> + sub(/^[a-z]+:\/\//,"",line)
> + at=index(line,"@")
> + if (at>0) {
> + creds=substr(line,1,at-1)
> + colon=index(creds,":")
> + if (colon>0) {
> + user=substr(creds,1,colon-1)
> + pass=substr(creds,colon+1)
> + if (index(pass,user)==1) { ok=0 }
> + }
> + }
> + }
> + END{ if (!ok) { print "Password appears prefixed by username"; exit 1 } }
> + ' "$app_yml"
> }
>  
> - # Write per-key SMTP entries (address/port/username/password)
> - # (legacy: performed via sed substitutions)
> - # NOTE: historically fragile with special chars
> - update_setting_yaml "DISCOURSE_SMTP_ADDRESS" "$smtp_address"
> - update_setting_yaml "DISCOURSE_SMTP_PORT" "$smtp_port"
> - update_setting_yaml "DISCOURSE_SMTP_USER_NAME" "$smtp_user"
> - update_setting_yaml "DISCOURSE_SMTP_PASSWORD" "$smtp_password"
> -}
> + # Legacy per-key writes removed in favor of atomic SMTP_URL write above.
> +}
> 
> ```
> 
> Why this meets your constraint  
> • Zero Ruby/Python on the host: only Bash + awk + od/printf/grep (all standard).  
> • No sed replacement of secrets: we avoid the “Bash → sed → YAML” multi-escape trap.  
> • Atomic-ish write: edit into a temp file, then mv over containers/app.yml.  
> • Backwards-safe: if env: doesn’t exist, we create it minimally; if it does, we update in place and remove conflicting DISCOURSE\_SMTP\_\* lines.  
> • Credentials are URL-encoded before insertion, so special chars in user/pass won’t break the URL parser in Rails/Net::SMTP.
> 
> If you’d prefer to keep the per-key variables instead of SMTP\_URL, I can send a sibling patch that (still without sed) uses the same awk strategy to set:
> 
> ```plaintext
> DISCOURSE_SMTP_ADDRESS
> DISCOURSE_SMTP_PORT
> DISCOURSE_SMTP_USER_NAME
> DISCOURSE_SMTP_PASSWORD
> 
> ```
> 
> …with YAML-safe double-quoted values and anchored replacements.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [15 september 2025 om 19:55 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/18 "2025-09-15T19:55:55Z")

</div>

> [@Ethsim2](#):
>
> Digital Ocean with Ubuntu 24.04 LTS

Then I can’t imagine how that happened. Can you replicate it as in my example?

Did you copy/paste all of the text in a single batch so that the buffer couldn’t keep up with how fast you were pasting?

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [17 september 2025 om 02:42 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/19 "2025-09-17T02:42:55Z")

</div>

hmmm ik vraag me af of we de logica gewoon in launcher2 kunnen bundelen, dan kunnen we die gebruiken om de installatie uit te voeren.  
De hoeveelheid horden waar discourse-setup overheen springt is spectaculair.

---

<div class="post-metadata">

### Author: ![Lhc\_fl](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lhc_fl/32/268115_2.png) [@Lhc\_fl](https://meta.discourse.org/u/Lhc_fl)
#### Post date: [17 september 2025 om 05:18 UTC](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710/20 "2025-09-17T05:18:59Z")

</div>

Is het mogelijk om de launcher te compileren tot een uitvoerbaar binair bestand voor release? Op deze manier kan de launcher (bash) alleen het bijbehorende uitvoerbare bestand (binair) downloaden op basis van het systeem.

[Next page](https://meta.discourse.org/t/discourse-setup-puts-smtp-username-at-start-of-smtp-password/381710.md?page=2)
