CC Customer On All Organisation Requests

44 Comments

  • Andrey Sarapulov

    Nice one Graeme!

    I've added a comment to my post referring to this article.

    0
  • Jennifer Rowe
    Zendesk Documentation Team

    This is great, Graeme, and, something a lot of folks are looking for. Thanks for sharing it!

    0
  • Ace Coven

    Great article, I've got a couple important questions myself and, I'm sure, others utilizing it would find especially clarifying:

    1. What do you recommend we use now that the single "value" parameter isn't an option? Specifically, the v2 API documentation states all incoming PUT params should be JSON. But clearly the Content type of the API allows for XML and Form input. So what should we use and what do you recommend we pass as the parameters? JSON:{ "ticket[collaborators]": "{{dc.extract_cc_mails_+|+prepend:','+|+prepend:{{ticket.organization.custom_fields.cc_user_on_all_organisation_requests}}"} doesn't seem like it would work.
    2. There are a couple places that look like they could be typos, but maybe not. Should {{dc.extract_cc_mails_+ be {{dc.extract_cc_mails+ ??? Similarly, you've got {{dc, {{ticket, and }} at the end. So it is really going to correctly parse two {{'s and only one }}, or does that need to be corrected, too?

    Thanks!

    0
  • Graeme Carmichael
    Community Moderator

    Andrew

    Thank you for your feedback. I must have got lucky and the CC still operated correctly. I have updated the text as you suggested as clearly you are correct.

    For your first point, on value parameter, unfortunately, I do not know the answer. I am not seeing any change on my account.

    0
  • Ace Coven

    For those of you that don't have the "value" option, the JSON option seems to be working with me. When you create your trigger, it will ask you what to use for the JSON block, put this:

    {"field": "cc_user"}

    (Again, it's a dummy value, but it needs to be valid JSON.)

    Would love to hear if this is working for someone else consistently. I have it working, but it's not consistent.

    0
  • Ace Coven

    A few days later and I can report the JSON field works just fine, so for those folks that don't have access to the Value only. JSON with the dummy {"field": "value"} works.

    I've also discovered another optimization to the "extract_cc_mail" dynamic content routine that seems to have been copy and pasted quite a bit, if anyone's interested:

    I did a little reading up on Liquid and the {% for %} loop automatically checks for empty--in fact, you can use an {% else %} before the end of the {% for %} loop to indicate a state when there are no items to iterate (such as "Nobody"). Given this, you can dramatically simplify your extract_cc_mail routine to:
    {% capture ccedusers %}{% for cc in ticket.ccs %}{{ cc.email }}{% unless forloop.last %}, {% endunless %}{% endfor %}{% endcapture %}{{ ccedusers | strip_newlines }}

    Hope this helps.

    0
  • Jessie Schutz
    Zendesk Customer Care

    Hi Andrew!

    Thanks for sharing your solution! :)

    0
  • Ace Coven

    Spent some more time hacking on this tonight, there's an even more efficient way to do this work. The MAP function in Liquid takes an array and automatically iterates through it and can pull out a specific named part of it (in this case, "email") and then join it together in a string with your given text, in this case ",":

    So all of this:

    {% capture ccedusers %}{% for cc in ticket.ccs %}{{ cc.email }}{% unless forloop.last %}, {% endunless %}{% endfor %}{% endcapture %}{{ ccedusers | strip_newlines }}

    Becomes this:

    {{ ticket.ccs | map: 'email' | join:',' | strip }}

    strip not only removes newlines, it also removes leading and trailing spaces.

    0
  • Pierre Merrien

    Hi,

    Does anyone have any idea how I get the same thing working using a custom field of mine (Drop-down)

    https://company.zendesk.com/api/v2/tickets/{{ticket.id}}.json+?ticket[collaborators]={{dc.extract_cc_mails+|+prepend:','+|+prepend:ticket.ticket_field_24561309 == gen_cc}}

    Doesn't work with field ID? 

    This is a custom drop-down field to select a value within, based on the tag gen_cc

    ticket.ticket_field_24561309 == gen_cc

     

    Kind regards,

    Pierre

    0
  • Jessie Schutz
    Zendesk Customer Care

    Wow, Andrew! Look at you go! :) Thanks again for sharing!

    0
  • Mike

    Nice solution however I need to be able to CC different end users based on ticket content not organisation, any ideas?

    Thanks,

    Mike.

    0
  • Ace Coven

    Graeme and Jessie,

    I am so appreciative of this initial script. This is the best way for me to learn and get things done for our company. I also believe in giving back to the originator and the community to make us all better. So I'd like to show you what I've found and collect a few of my other comments into one:

    1) The Extension and HTTP target has two bugs:

    1a) We no longer have access to the "value" option, so we should use "JSON". And it turns out an empty JSON packet works the best, so just: {}. I experimented using {"ticket":{"collaborators":["a@b.com","b@c.com"]}} and due to a limitation in it not expanding "{{dc.extract_cc_mail}}" into individual entries, that approach will not work. So just use a blank packet: {}

    1b) You do not need the space between .json and ?, so .json+? should just be .json?

    1c) The HTTP target URL is the way to provide multiple collaborators as a comma delimited list with no spaces. But if your CC field is BLANK, the current implementation fails because it will put a stray "," in front of the list, causing the URL call to silently fail. The correction is to move this logic into the extract_cc_mail routine. This optimization also has the benefit of it will be the way Pierre and Mike can both solve their problems, as well. More on that in a follow-up comment. So instead of this:

    https://YOURDOMAIN.zendesk.com/api/v2/tickets/{{ticket.id}}.json+?ticket[collaborators]={{dc.extract_cc_mails+|+prepend:','+|+prepend:ticket.organization.custom_fields.cc_user_on_all_organisation_requests}}

    Have everyone do this:

    https://YOURDOMAIN.zendesk.com/api/v2/tickets/{{ticket.id}}.json?ticket[collaborators]={{dc.extract_cc_mails}}

     2) Extract_cc_mails has a number of optimizations I've recommended. You started with this:

    {% if ticket.cc_names != empty %}{% capture ccedusers %}{% for cc in ticket.ccs %}{% unless forloop.last %}{{ cc.email | append: ', ' }}{% else %}{{ cc.email }}{% endunless %}{% endfor %}{% endcapture %}{{ ccedusers | strip_newlines }}{% else %}{% endif %}

     

    And then I found that Liquid will automatically skip an empty loop, so you don't need the IF at the beginning. I also then found that Liquid has a STRIP command that will also strip leading and trailing whitespace (needed to compact a multi-user email list--we can't validate that our users won't enter "a@b.com, b@c.com" with a space in between, or maybe even "a@b.com; b@c.com", so we can bulletproof a little more.

    There is also MAP and JOIN commands that allow us to pull a field right from a structure and iterate automatically. This dramatically reduces the extract_cc_mails. But now we need to introduce the logic to not only grab the CC field, but also add the CC Org users field. So we end up with a dc.extract_cc_mails routine that looks like this:

    {% assign ticket_cc = ticket.ccs | map: 'email' | join:',' | strip %}{% assign org_cc = ticket.organization.custom_fields.cc_user_on_all_organisation_requests | remove:' ' | remove:'<' | remove:'>' | remove:'"' | remove:'?' | replace:';',',' | replace:'+','%2B' | strip %}{{ ticket_cc }}{% if ticket_cc.size > 0 and org_cc.size > 0 %},{% endif %}{{ org_cc }}

    What this does is create two variables, one for the ticket's CC list, and one for the Org's CC list. It sanitizes each set of data--the ticket's CC is well sanitized and validated by Zendesk when it's first entered, but the Org CC list could have a lot of inappropriate parts, so we remove all the obvious ones that would cause failure. It then prints out the cleaned up and condensed ticket's CC (if it's not empty), checks to see whether it needs to join them with a ","--prints that, if so, and then prints the cleaned up Org CC.

    This has the benefit of putting the logic into code that can be controlled vs the HTTP target. So both Pierre and Mike, for instance, can then add the specific logic (or different field names) to the dynamic content script.

    Hope this helps!

    0
  • Andrey Sarapulov

    @Andrew,

    Re point 1a i won't call it a bug. Target V1 and Target V2 are two different features. This post is based on idea which i describe in another article where I used Target V1. For Targets V1 you can specify "value" attribute. While for Targets V2 its different. On my test account i can choose which target to use (see link below).

    https://www.evernote.com/l/AQOiIR8gApdPhIa1nwFQwn_xMKCPkwrNWc0

    0
  • Petri Rossi

    Hello,

    first, thank you guys for sharing a solution to help on a daily recurring task. This would be very valuable for us as our agents are currently adding CCs manually on every ticket on a daily basis. However, I'm having some problems getting the solution to work (testing first in our SANDBOX). Pardon my newbiew question (not familiar with Liquid).

    I first added Organization Custom field (cc_user_on_all_organization_requests) as described.

    Then set up dynamic content (dc.extract_cc_mails):

    {% assign ticket_cc = ticket.ccs | map: 'email' | join:',' | strip %}{% assign org_cc = ticket.organization.custom_fields.cc_user_on_all_organisation_requests | remove:' ' | remove:'<' | remove:'>' | remove:'"' | remove:'?' | replace:';',',' | replace:'+','%2B' | strip %}{{ ticket_cc }}{% if ticket_cc.size > 0 and org_cc.size > 0 %},{% endif %}{{ org_cc }}

    After a quick browse of the Liquid syntax documentation this seems logical and should work from what I can tell.

    I have set up an HTTP Target extension to use this (with "<MYDOMAIN>" replaced with our actual SANDBOX domain):

    URL: https://<MYDOMAIN>.zendesk.com/api/v2/tickets/{{ticket.id}}.json?ticket[collaborators]={{dc.extract_cc_mails}}
    Method: PUT
    Content type: JSON
    Authentication: <email>/token (with valid e-mail address) and API Token for password


    ..and finally a trigger to run at ticket create to push to the target, with an empty JSON Body:{}

    I also tried the following versions for the JSON Body in the trigger with no success:

    {"field": "value"}

    {"field": "cc_user"}

    I can see in a test ticket that the trigger pushes to the target. However, I'm not getting any CCs added in the created ticket. Can anyone point out where I'm going wrong? Help would be greatly appreciated.

    0
  • Graeme Carmichael
    Community Moderator

    Petri

    Tricky isn't it? 

    To use the new URL Target, Andrew recommends using {} as the JSON content.

    I have found that works for me, but only if I use the original URL in the article.

    https://YOURDOMAIN.zendesk.com/api/v2/tickets/{{ticket.id}}.json+?ticket[collaborators]={{dc.extract_cc_mails+|+prepend:','+|+prepend:ticket.organization.custom_fields.cc_user_on_all_organisation_requests}}

    and not the revised URL that you have mentioned. 

    Using the revised URL, I get the same as you. The extension can be tested successfully, fires on the ticket but no CC is added.

    I am that sure Andrew will be better at explaining the process than me. But, that might get you started.

    0
  • Petri Rossi

    Hi Graeme,

    thanks for your quick response! I tested that and indeed it works! However, I tested it now on our production Zendesk.

    It seems for some reason that didn't (still doesn't!) seem to work on my Zendesk SANDBOX (also, adding CC through API did not seem to work on SANDBOX, which led me to carefully try it out in production).

    0
  • Ace Coven

    Hi you two! Check to make sure the field name is the same, because there's a little bit of translating we've done between the British english spelling vs. the American english spelling. That is, make sure:

    ticket.organization.custom_fields.cc_user_on_all_organisation_requests

    Is correctly spelled (vs. what you've used) and:

    {{dc.extract_cc_mails}}

    Is also the same name.

     

    0
  • Graeme Carmichael
    Community Moderator

    Thanks Andrew!

    0
  • Ace Coven

    How about some open kimono to help give back to the community! Now, I've taken what Graeme wrote and made it a little more complicated to account for a couple Zendesk bugs or limitations in their Liquid implementation (2.6.2)...

    Here's my field name:

    cc_users_on_all_organization_requests

    Here's my dc (note that I talked to Zendesk support, and they do not support the latest Liquid implementation so "strip" doesn't do anything, you can use "strip_newlines"):

    {{dc.extract_cc_emails}}

    {% assign ccs = ticket.ccs | map:'email' | join:',' | append:',' | append:ticket.organization.custom_fields.cc_users_on_all_organization_requests | strip_newlines | remove:' ' | remove:'<' | remove:'>' | remove:'"' | remove:'?' | replace:';',',' | downcase | replace:'+','%2B' | prepend:'%start%' | remove:'%start%,' | remove:'%start%' | append:'%end%' | remove:',%end%' | remove:'%end%' | split:',' | sort %}{% assign new_ccs = '' %}{% for cc in ccs %}{% if cc.size > 3 %}{% assign cc_bookends = '%start%' | append:cc | append:'%end%' %}{% unless new_ccs contains cc_bookends %}{% assign new_ccs = new_ccs | append:cc_bookends %}{% endunless %}{% endif %}{% endfor %}{% assign new_ccs = new_ccs | replace:'%end%%start%',',' | remove:'%start%' | remove:'%end%' %}{{ new_ccs }}{% comment %}We do this horrific for loop to check for duplicates because Zendesk only supports Liquid 2.6.2, which doesn't have strip or uniq. So if someone specifies the same email twice in the org_cc, it'll make two copies in the ticket cc.{% endcomment %}

    Here's my trigger, which also sends me an email every time it does this so I can see that it's working correctly:

    The JSON blanks out collaborators due to the bug of having duplicates:

    {"ticket":{"collaborators":[]}}

    The Email body (if you want to use it for debugging) is:

    dc.extract_cc_emails:
    [{{dc.extract_cc_emails}}]
    ticket.organization.custom_fields.cc_users_on_all_organization_requests:
    [{{ticket.organization.custom_fields.cc_users_on_all_organization_requests}}]

     

    And here's the HTTP target:

    And the URL from the put:

    https://instartlogicinc.zendesk.com/api/v2/tickets/{{ticket.id}}.json?ticket[collaborators]=&ticket[collaborators]={{dc.extract_cc_emails}}

    Yes, there are TWO ticket[collaborators], because there is a bug where it doesn't clear out the previous one before adding the new people and can get duplicates.

    One last thing: I've noticed when staring at a ticket and adding a "ccadd" comment that the ticket WILL get updated but the CC field sometimes doesn't show the latest content, so I always manually force-refresh the page in my web browser that is showing a ticket after I've seen the trigger run to make sure the CC field is showing the latest updated information.

    Hope this helps!

    ...A

    0
  • Petri Rossi

    @Andrew,

    good catch, thanks! The problem was indeed between British and American english in the DC vs. Organization field name.

    0
  • Jennifer Rowe
    Zendesk Documentation Team

    Hi Petri, glad you got it working!

    Andrew, thanks for your help for for posting your solution! If you'd like to post your modified solution as a separate new tip for users (with a link back to Graeme's original) we'll send you swag. :)

    Thanks for being part of the community!

    0
  • Ace Coven

    Hi Jennifer! I'd be happy to, but I'm really just advancing Graeme and Andrey's work, so it seemed appropriate to post in their articles. If you all feel otherwise, just ping me at my email and we can discuss!

    0
  • Yannick Laurent
    Hi all,
     
    Great tip for adding CC !
     
    Does someone has a great tip to notify by email these new CCed users when ticket is created ? (and only these new ones)
     
    Initial CCed users will automatically received an email notification when ticket is created, it's seem to be by design. But these custom added CCed users will not, because of asynchronous API call.

     

    0
  • Ace Coven

    @Yannick,

    Actually, the "Email users on new ticket" looks to be a trigger, so as long as you have this trigger run AHEAD of that, you will, in fact, get these people emailed as part of the initial creation alert. Have you seen the upper right "edit" button to the triggers page that allows you to drag their order around?

    Cheers,

    ...A

    0
  • Yannick Laurent

    Hi Andrew,

    Here is my ticket events :

    1/ First event : new ticket including a existing CC user

     

     

     

    We see notifying CC is not a trigger, it's integrated in my Zendesk.

    2/ Second event, result of URL target's trigger (add a second CC user) :

     


    even if the URL target trigger is set at the top, it's an asynchronous process. So CC email ("YL public") added by web service is not present at the time of the first event. It comes as a second event, after CC notification occured in the first event.

    So...Is it possible we have not the same Zendesk platform ? or I missing something...

    0
  • Dan Spataru

    This is brilliant! 

    Thanks for sharing!

    0
  • Daniel Spring

    I've tried variations with both target URL and target HTTP and though I can prove that my constructed CC list is be built correct, I'm never actually seeing the emails added to the CC list of the ticket. :-(  Do the emails have to be registered with existing user accounts?  I was hoping to use this technique as a way to get around that silly limitation in Zendesk, and considering the purpose of this post, I assumed this made it possible to do so.  The emails I'm trying to add through the target HTTP do not exist as users in our ZD instance, so I'm wonder if that's why I'm never seeing the emails added to the CC list.

    0
  • Ace Coven

    @Yannick: I think you're on to something. Because I've noticed similar when I've wanted to add a Cc'ed user and have them see a comment I'm adding, I can't do them at the same time. I have to add the Cc'ed user, submit as open, then add the comment, then submit as open. So you must be right that there's a non-deterministic ordering going on.

    @Daniel: you definitely do NOT need these people to be valid Zendesk accounts, as you say, it's a way around that whole problem. It sounds to me like maybe your HTTP or URL target might be misconfigured--did you actually do the test option and see a reasonable response? Because when you test it you should get the resulting record back of a test record. Here's another thing you can do, too: add an "email" event that emails just you every time the trigger runs and have it send you the {{dc.extract_mail_ccs}} in the body of the email and you'll be able to see if that's resulting in anything meaningful.

    0
  • Hossam Medhat

    This is amazing Graeme,

    I have 1 question. I got the trigger & the target working, but the notification email is not sent to the CC-ed person added by the trigger after the ticket creation. However, the email is sent after the first reply. Meaning that the newly added CC is not notified with after the ticket creation.

     

    Any ideas, how can I overcome this problem?

    Thanks,

    0
  • Graeme Carmichael
    Community Moderator

    Hossam

    Sorry to say that the newly added CC not being notified on the ticket creation is a limitation of this approach.

    You may want to explore the user settings. If you give a user access 'to view tickets from 'user's org', the user will then have the option to 'follow' all organisation requests. The user can either set this up, or you can assume their identity and set it up for them.

    0

Please sign in to leave a comment.

Powered by Zendesk