I’m going to show off Midi The Cat at the Norwich Gaming Festival in a couple of weeks, and one thing I wanted to have is a form after the victory screen for players to sign up to the mailing list.
I had my Unity UI for the submission, but wanted to be GDPR compliant by doing the double-opt-in stuff where it sends a confirmation email and that jazz.
After some research, it seemed a good solution would be to use MailChimp – a web service for storing email contacts and sending out bulk emails.
This is when the fun began.
After making a MailChimp form that matched my data fields (email and feedback string), I wanted to push to it from Unity.
My initial approach was to use a push request to the form page directly, and with some wrangling had something that looked like this:
[csharp]
m_form = new WWWForm();
m_form.AddField("MERGE0", m_emailInput.text);
m_form.AddField("MERGE1", m_feedbackInput.text);
// Some extra hidden fields that I apparently need to fill in my form?
m_form.AddField("u", "1f271a9e997836765ea218377");
m_form.AddField("id", "bef723ffb7");
using (var w = UnityWebRequest.Post("https://gaminggarrison.us18.list-manage.com/subscribe/post?u=1f271a9e997836765ea218377&id=bef723ffb7", m_form))
{
yield return w.SendWebRequest();
if (w.isNetworkError || w.isHttpError)
{
Debug.LogError(w.error);
OnFailure();
}
else
{
Debug.Log("Submission successful!");
OnSuccess();
}
}
[/csharp]
Now apart from finding out you needed to fill hidden form fields, this looked reasonable.
Unfortunately I was hitting this error: 411 Content Length Required
Now, I can’t easily upgrade my Unity, because I tried 2017.4 and it horribly broke my UI (randomly positioning it offscreen – probably due to some uninitialised positions when my script was running, but I didn’t want to put workarounds everywhere).
So after some more googling, I found out that you needed the magic work-around line:
[csharp]
w.chunkedTransfer = false;
[/csharp]
before you SendWebRequest();
and everything will be fine. Well, yes, it seemed fine – I actually managed to submit a test email, and get the opt-in email and everything.
Unfortunately, testing a second time came out with nothing, and a third time…
I tried using the form directly, yes it works there – but it popped up an “Are you Human” captcha, so that’s probably it isn’t it – the captcha was breaking my form submission.
I went through the settings in MailChimp, and I had the re-captcha turned off, but I’m guessing they have something on at all times, so this wasn’t going to pan out.
Back to the Drawing Board
Now I was vaguely aware that MailChimp had a RESTful API (which is v3 ATM), so I figured – I’ll just use that so I won’t be suckered by surprise captchas.
The first thing you’ll find if you google this stuff is huge github repos like MailChimp.net, but I didn’t want to muddy my whole game just for a simple web request, and ‘fortunately’ I managed to find a simple and promising looking example: https://github.com/fiftytwo/MailChimpSubscriber
Of course, trying that just gave me failed post responses, with “generic http error” messages – how useful. (I found out later that if your API actually returns nice error data, as MailChimp does, request.downloadHandler.text is MUCH more useful than request.error)
Maybe it was breaking because it was using Unity’s deprecated WWW API? Thus I converted it to use UnityWebRequest. Still no luck. I was banging my head against the wall at this point, blaming everything from the auth to the data json, so I went looking for some web-request debugging tools, first finding WizTools Rest Client and then the much more modern (and helpful) Postman.
Now I could test my post request, with the auth header and json body and find the error – when of course, it worked first time.
I figured it had to be my code somehow, and I spent quite some time double checking, Debug.Log’ging, and generally going over my references to see if I was missing something.
At this point I’m questioning whether UnityWebRequest even sends my data and doesn’t just throw random garbage at the window, so of course, I try building the UTF8 byte array manually and…
It works! I’m saved! It only took me the better part of a day to solve a one-liner problem! …but why didn’t it work before??
Turns out, yes, I’d found a bug in Unity again :-/
Specifically, this bug.
For me, this meant that this call on my post request
[csharp]
www.SetRequestHeader("Content-Type", "text/plain");
[/csharp]
was actually doing nothing (well, maybe it sets the header, but the post data doesn’t get packed as UTF8 – though the documentation implies it).
so now, instead I have:
[csharp]
www.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(data));
www.uploadHandler.contentType = "text/plain";
www.SetRequestHeader("Authorization", "apikey " + _apiKey);
//www.SetRequestHeader("Content-Type", "text/plain"); // Doesn’t work due to bug in 2017.3 :@
[/csharp]
and of course the
[csharp]
www.chunkedTransfer = false;
[/csharp]
So that’s it folks, remember to check that your simple library call is actually doing anything near what you expect it to do. Maybe you’ll even save time by reading Unity’s bug reports BEFORE checking your own code. 😉