Returning case-sensitive input of case-insensitive array match
First of all, you should mention that you are using the additional module citext that provides the case insensitive text data type citext, which is not strictly needed here. The solution below only requires standard Postgres 9.4.

Key elements are jsonb_each_text() to unnest jsonb values into key/value pairs and json_object_agg() to re-assemble the JSON value with changed parts:

SELECT j.id, json_object_agg(d.key, CASE WHEN d.key = 'email'
                                         THEN t.email ELSE d.value END)::jsonb AS d
FROM   jsonthings j
JOIN   unnest('{TEST1@TEST.COM,test3@test.com}'::text[]) t(email)
                                                ON lower(t.email) = lower(j.d-&gt;&gt;'email')
     , jsonb_each_text(j.d) d
GROUP  BY 1;


Result:

id | d
---+---------------------------------------
1  | {"id": "1", "email": "TEST1@TEST.COM"}
3  | {"id": "3", "email": "test3@test.com"}


How?

(0.) Of yourse your table has a primary key you did not mention. Let's call it id.


Unnest the text array into individual rows and JOIN to the 'email' value of the jsonb column using lower() on both sides to make it case insensitive.
Decompose the jsonb column (only identified rows!) into key/value pairs with jsonb_each_text().
Replace original 'email' values with the search string with a CASE statement.
Finally aggregate everything back to a json object with json_object_agg() and cast to jsonb. 


Aside: For a simple structured form like you present in the example, a normalized schema with scalar Postgres data types would be much more efficient:


How to perform update operations on columns of type JSONB in Postgres 9.4