Script for sending welcome message in background

Hello,

I’m interested in sending a welcome message to our large user base as a background process, so:

  • Create the message
  • Queue users
  • Send message to each user, one at a time, one per second until the full list is done
  • Also would like to organize the send by most recent login/visit

Does anyone have any idea how to do this, or if someone can write a script to do this?

ask.discourse.org output a good starting point, as a rails script:

MAX_MESSAGES = 1000 # Optional limit for testing
SECONDS_BETWEEN_MESSAGES = 3 # 3 second interval

Rails.logger.info "Starting bulk message script..."

# Define the content of your message
message_title = "Welcome to Our Community"
message_body = "Hello! We're so excited to have you here. Let us know if you have any questions!"

# Fetch users ordered by last seen
users = User.where(active: true)
            .where.not(staged: true) # Exclude staged users
            .order(last_seen_at: :desc)
            .limit(MAX_MESSAGES)

Rails.logger.info "Found #{users.count} active users to message."

users.each_with_index do |user, index|
  begin
    Rails.logger.info "Queuing message for #{user.username} (#{index + 1}/#{users.count})..."

    PostCreator.create!(
      Discourse.system_user,
      title: message_title,
      raw: message_body,
      archetype: Archetype.private_message,
      target_usernames: user.username,
      skip_validations: true
    )

    Rails.logger.info "Message successfully queued for #{user.username}."

    # Wait for the specified interval before processing the next user
    sleep(SECONDS_BETWEEN_MESSAGES)
  rescue => e
    Rails.logger.error "Failed to send message to #{user.username}: #{e.message}"
  end
end

Rails.logger.info "Bulk message script completed!"

I didn’t do any modification, and the user system sent the MP to all my users in my test instance:


How many users do you have?

4 Likes

@CocoQuark first that’s an amazing handle…but your response is even more amazing! This is really right along the lines of what we want to do. Some more detail.

We have 3.5 million users. We do not plan to send to all of them at once, the idea would be to run this script, maybe for batches of 10k, then stop for a few days, see what kinda of activity we have, check email reputation, and then start again, and so on.

We would like to send this though from an admin with a profile rather than ‘system’, I assume that’s possible?

Again, thanks so much, very very helpful.

2 Likes

Yes, just replace system with the desired username in the script.
Sorry, I skimmed the code, there is no system to replace, so it must be done another way.

You’ll probably want to use a session manager like screen or tmux so your script can run in the background.

I assume you’ll also want to be able stop the script when desired and restart it later from the user it stopped at.

Since I’m not a programmer (I mean, besides printing hello world…), I’ll let others give advice on how to set up this feature properly, as well as safely managing the sending to millions of users :smile:

1 Like

@CocoQuark All sensible, and thanks. Yes I am thinking there is a way to just do some sort of count of records the system would run through, so basically it would just stop itself, but understood on the other options.

If anyone else has any ideas on how to make this more automated (run for batches of 10k users for example) that would be great.

Yeah. If I were to create this kind of script, I’d set up something that would allow me to restart from the last user in case the script is forcibly interrupted by something (server restart, crash…, etc.).

Here’s the updated script with the sender username:

MAX_MESSAGES = 1000 # Optional limit for testing
SECONDS_BETWEEN_MESSAGES = 3 # 3 second interval
SENDER_USERNAME = "coco"

message_sender = User.find_by(username: SENDER_USERNAME)

if message_sender.nil?
  Rails.logger.error "Sender user '#{message_sender_username}' not found!"
  exit
end

Rails.logger.info "Starting bulk message script..."

# Define the content of your message
message_title = "Welcome to Our Community"
message_body = "Hello! We're so excited to have you here. Let us know if you have any questions!"

# Fetch users ordered by last seen
users = User.where(active: true)
            .where.not(staged: true) # Exclude staged users
            .order(last_seen_at: :desc)
            .limit(MAX_MESSAGES)

Rails.logger.info "Found #{users.count} active users to message."

users.each_with_index do |user, index|
  begin
    Rails.logger.info "Queuing message for #{user.username} (#{index + 1}/#{users.count})..."

    PostCreator.create!(
      message_sender,
      title: message_title,
      raw: message_body,
      archetype: Archetype.private_message,
      target_usernames: user.username,
      skip_validations: true
    )

    Rails.logger.info "Message successfully queued for #{user.username}."

    # Wait for the specified interval before processing the next user
    sleep(SECONDS_BETWEEN_MESSAGES)
  rescue => e
    Rails.logger.error "Failed to send message to #{user.username}: #{e.message}"
  end
end

Rails.logger.info "Bulk message script completed!"
3 Likes

That is bonus @CocoQuark - we will run this likely tomorrow, if we adjust further we will post back here with updates…

CC: @Abdelrahman_MoHamed

1 Like

Likely, you’ll need to edit this line:

My last reply already contains the needed changes.

3 Likes

Another question here. Does anyone have any idea how to keep track of where the script is in the process? For example we send 10k emails and stop. Then want to start again, how would we know which record to start with?

1 Like