Creating a staged user with an API call

We currently have a workflow where users submit data by sending an email to a custom incoming email address, creating a staged user and a private message to a Discourse group.

Is it possible to achieve the same workflow using API calls? Basically 1) create staged user, 2) generate API key for that user, then 3) post on that users behalf? I see how to post group messages for existing users using the API docs, but don’t know if steps 1) and 2) are possible currently.

4 Likes

Yes, just create a user via the api. They won’t be “staged” at this point since they actually exist. If they ever need to log in, they can just reset their password.

This is also possible


Here is a rough example of how to create a user, active them, and generate an api key for them.
    def create_user
      user = {
        name: example1,
        email: "example1@example.com",
        password: "ZvAmmkcSWQfsPQLBksg7wK59",
        username: example1,
        active: "false",
        approved: "true",
        approved_by_id: 1,
        approved_at: DateTime.now
      }

      new_user = @client.create_user(user)
      id = new_user['user_id']
      @client.activate(id)
      uri = URI.parse(@config.full_discourse_url)
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      request = Net::HTTP::Post.new("/admin/users/#{id}/generate_api_key?api_key=#{@client.api_key}&api_username=#{@client.api_username}")
      response = http.request(request)
      result = JSON.parse(response.body)
    end

Another option instead of generating an api key for each user is you can just instantiate a new discourse client using the same admin api key and just specify the new username:

client = DiscourseApi::Client.new("http://127.0.0.1:3000")
client.api_key = "a71cb5058c6be27e42806ad788bc7b0008af9c15170d1be1827a24c8e8334107"
client.api_username = "system"

... create user here...

client2 = DiscourseApi::Client.new("http://127.0.0.1:3000")
client2.api_key = "a71cb5058c6be27e42806ad788bc7b0008af9c15170d1be1827a24c8e8334107"
client2.api_username = example1

... create post here ...
10 Likes

I’m trying to avoid creating a full-fledged user account and picking a username. Essentially I want to replicate whatever is happening in the email trigger (‘custom incoming email address’ in the group settings) where the sender’s email address will be ‘staged,’ such that if/when they do register, they’ll be able to claim any messages that were created on their behalf via the email trigger.

Does that make sense? Is there a way to ‘spoof’ an incoming email using API calls? Thanks for all your help!

You might just have to generate an email and send that to your Discourse instance.

EDIT: Actually there is an /admin/email/handle_mail POST route that you can send an API request to.

8 Likes

Thank you, this is exactly what I was looking for!

1 Like

Could you specify, what headers and fields should be in the API call to /admin/email/handle_email that creates a staged user and a topic on his behalf?

Also, did I get it right, that such a user will receive notifications for new posts in such a topic and will be able to reply to it via email?

And what happens, if I try to create a staged user and a topic via an API call with an email address that belongs to an active user? Will this topic be created on behalf of such user?

I already found out, that the correct endpoint is /admin/email/handle_mail (not “handle_email”), but still can’t figure out, what should be in the API request.

1 Like

The only parameter this endpoint takes is a valid email message:

curl -i -sS -X POST "http://localhost:3000/admin/email/handle_mail" \
-H "Api-Key: 852b2d8556777aeb62346e0d8b36ed248a89b03f0261165a685c0aae9c8c2fdd" \
-H "Api-Username: system" \
-F "email=Date: Mon, 24 Feb 2020 13:13:34 -0700
From: stageduser2@example.com
To: awesome@example.com
Subject: test email5

This is a sample email message.
"

You will need to make sure you enable email_in correctly setup your category or group to receive these emails:

Yes, I believe so.

Yes, the topic will be created on behalf of the user.

5 Likes

Thank you, Blake. However, it still doesn’t work for me. I got a response from API “email has been received and is queued for processing”, but nothing appears in Discourse - neither a new topic, nor a staged user.

Here’s the review of the settings:
Global:

  • email_in: on
  • email_in_min_trust: 0
  • enable_staged_users: on

Category:

  • Custom incoming email address: set as [my_name]@gmail.com
  • Accept emails from anonymous users with no accounts: on

API call:
curl -i -sS -X POST "[my_domain]/admin/email/handle_mail" -H "Content-Type: multipart/form-data;" -H "Api-Key: [...]" -H "Api-Username: system" -F "email=Date: Mon, 24 Feb 2020 13:13:34 -0700 From: [some_name]@gmail.com To: [my_name]@gmail.com Subject: test API email post This is a sample email message."

What could be wrong?

Is your sidekiq running properly?

How can I check that?

You can check if sidekiq is running by browsing to /sidekiq, but I think there is likely an issue with the raw email now that the api request is succeeding. There are several tabs in the admin dashboard you can check for email errors.

  • /admin/email/sent
  • /admin/email/skipped
  • /admin/email/bounced
  • /admin/email/received
  • /admin/email/rejected

See if you can find the emails you are creating via api calls under one of those tabs and you might be able do see an error message associated with it.

1 Like

Yes, sidekiq is running. I checked the /admin/email tabs - looks like my “emails” are actually rejected.
This is what I get:

I inserted the same email text in the “Advanced text” tab, and it seems to be working, if each part (Date, From, To, Subject) starts with a new line, and the body is separated by two line breaks. When inserting the text exactly like in curl, it returns nothing. Could it be the line breaks in the raw email? If yes, what should I do?

I tried, /n, %0A and $'[text/n]', neither works.

I’m not sure. Looks like it doesn’t like any of the fields in your email.

I used ruby to generate the curl command and ruby to read my email text file I wrote, but yes it appears to be a newline issue.

Can you have curl read an email file that has actual newlines in it?

curl -X POST -i -F parametername=@filename host:port/xxx

3 Likes

You were right - that was a newline issue. I tried the same API call from Postman, and it worked - a new staged user was created and a topic on his behalf.

But: no email was sent to this user’s address! I also posted a comment in the topic - no email notification either. Is there a setting that prevents this? I tried to find one, but I couldn’t.

UPD: There was a indeed a setting that prevented sending post notifications :slight_smile: so now I have two different questions:

  1. Why there wasn’t an email informing the staged user that the topic was created and sending him the link to it?
    (I would also add some instructions about how to log in to the forum if I knew, which template to edit.)
  2. Why there’s no link to the topic in the post notification emails? Also no unsubscribe link.
    The template seems to be the same - “user_posted”.

Which setting for anyone following along? I don’t think I had to change anything, so just curious.

I think this is by design and the same happens if you send an email to a Discourse group. It is designed to work just like email as in the user might not even know they are sending an email into a Discourse forum. If I send you a regular email to your email account I don’t get a reply back from your email provider that says you received my email, we just trust that it works.

Here is an example email notification a staged user will receive:

image

but this is what a non-staged user will receive:

There appears to be a difference between staged users and non-staged users. Likely because the user is staged it is to be just like interacting via regular email.

2 Likes

There actually were several.

  • default email level - default is “only when away”
  • email time window - default is 10 minutes, so the notification email is not sent immediately
  • disable emails - default is “no”, but I had it changed before and forgot about it :man_facepalming:

Well, for me the post notification doesn’t really look like a regular email anyway - e.g. it has a link to the post author’s profile at the forum (twice!), but not to the topic.

Besides, I would like to inform the staged user, that he can actually sign in to the forum.
Is there a way to customize this email template?

By design there are several fields that are omitted for staged users in email templates (like the respond instructions):

https://github.com/discourse/discourse/blob/3568f296a3477d3f17ee2a63a247a3dc8e49c900/app/mailers/user_notifications.rb#L647

I’m not entirely sure of the reasoning, jut stating that in code this is how it is, so you are currently fighting an up hill battle here because you are attempting to do something discourse is designed not to do.

Yes, you can edit the email templates, but you are pretty limited in what you can customize. Like I don’t think you can customize the email template to look one way for staged users and another way for non-staged users, but you can add a message with a link to the bottom of the notification email inviting them to visit your site instead of just interacting via email.

1 Like

Actually, it would be enought if the template looks the same way for regular and staged users :slight_smile:
I’ll think, what I could do. Thank you for the detailed explanation!

3 Likes

One last question (hopefully): how can a staged user unsubscribe from receiving new posts to the topic created on his behalf?