Du gehst sehr verschwenderisch mit deinem RAM um. Davon gibt es nicht viel. Alle String Literale werden am Anfang automatisch ins RAM kopiert.
Mach mal überall wo du print() Anweisungen hast (sowohl bei Serial aus auch Client) ein F() um den String. So:
Serial.println(F("String im Flash"));
Dann bleibt das im Flash.
Und lass diesen Blödsinn sein:
client.print("&key=" + String(key));
Mit der String Klasse machst du Schweizer Käse aus deinem RAM. Vor allem bei solchen unnötigen Konkatenierungen. Dem Ethernet Controller ist es völlig egal ob du da zwei print() Anweisungen hintereinander machst oder ob das in einem String steht.
Was du du machst ist folgendes:
1.) Dynamischen Speicher anlegen und "key" da rein kopieren
2.) Noch mehr dynamischen Speicher anlegen und die zwei Strings zusammenfügen
3.) Den ersten Speicherbereich wieder freigeben
Zusätzlich belegen die zwei Strings noch statisch RAM. Statt dessen einfach:
client.print(F("&key="));
client.print(key);