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:
@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?
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
@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!"
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?