Since at least October 2016, the official API provides a way to add permanently visible labels that are longer than one letter. See this reply by a Google project member.
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: 'Hello world',
});
By default, the result looks like:

Pretty unreadable. Fortunately the API also allows a MarkerLabel object instead of a plain string:
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: {
color: 'white',
fontWeight: 'bold',
text: 'Hello world',
},
});
Snippet above yields the following result:

However, the original question asked if the label could be located below the marker. The MarkerLabel docs mention this is possible with a custom icon and labelOrigin
property. If we want to use the default icon, one is available at GitHub. Let us add the icon object:
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: {
color: 'white',
fontWeight: 'bold',
text: 'Hello world',
},
icon: {
labelOrigin: new google.maps.Point(11, 50),
url: 'default_marker.png',
size: new google.maps.Size(22, 40),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(11, 40),
},
});
This results:

Pretty good! However, this whole approach has a shortcoming that the box in the original question does not have: readability with each map type. If the map type is changed from the satellite to the default the resulting label is hard to read:

An easy but not perfect way to avoid the low contrast in the both types is to set color: 'gray'
:

However, the gray color fails near urban areas. A better option would be to apply text-shadow
CSS property to draw black linings for the white text. However, I cannot find a way to apply the property to the labels because few DOM elements created by Google Maps define a class:

The best option I came up to is to detect changes in the map type and update label color for each marker:
map.addListener('maptypeid_changed', function () {
var typeToColor, type, color, k, label;
typeToColor = {
'terrain': 'black',
'roadmap': 'black',
'hybrid': 'white',
'satellite': 'white',
};
type = map.getMapTypeId();
color = typeToColor[type];
for (k in markers) {
if (markers.hasOwnProperty(k)) {
label = markers[k].getLabel();
label.color = color;
markers[k].setLabel(label);
}
}
});
However, even this would fail on snowy or cloudy satellite imagery. I think it is still good enough in most of the cases. Nevertheless, it is nice to have the ability to display visible labels with the official API, without any plugins :)