I'm trying to generate a vcard using the vobject library but I am running into a couple of issues.
First off, I've tried adding a photo using both a url and base64 data, but I cannot get the photo to display on the OS X contacts app (Mavericks), or a Galaxy S4 running Android 4.4.2 . I even tried this on my Lumia 1520 running windows phone 8.1, but to no avail.
The code is as follows:
card = vobject.vCard()
attr = card.add('n')
attr.value = vobject.vcard.Name(family=agent.last_name, given=agent.first_name)
attr = card.add('fn')
attr.value = agent.get_full_name()
attr = card.add('email')
attr.value = agent.email_address
attr.type_param = 'INTERNET'
attr = card.add('tel')
attr.value = agent.cell_number
attr.type_param = 'cell'
attr = card.add('tel')
attr.value = branch.get_telephone_number()
attr.type_param = 'work'
attr = card.add('org')
attr.value = "Moe's Co"
photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()
attr = card.add('photo')
attr.type_param = 'JPEG'
attr.value = photo_url
response = HttpResponse(mimetype='text/x-vcard')
response['Content-Disposition'] = 'attachment; filename="%s.vcf"' % agent.get_full_name()
response.write(card.serialize())
return response
This generates the following file:
BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:[email protected]
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=JPEG:http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD
The above method places the URL of the image as the photo. The code for the base 64 implementation (see here for more info) is shown below:
photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()
attr = vcard.add('photo')
attr.type_param = 'jpeg'
attr.encoding_param = 'b'
attr.value = base64.encodestring(data)
The result:
BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:[email protected]
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=jpeg;ENCODING=b:LzlqLzRBQVFTa1pKUmdBQkFRQUFBUUFCQUFELzJ3QkRBQU1DQWdNQ0FnTURBd01FQXdNRUJRZ0ZCUVFFQlFvSEJ3WUlEQW9NREFzSwpDd3NORGhJUURRNFJEZ3NMRUJZUUVSTVVGUlVWREE4WEdCWVVHQklVRlJULzJ3QkRBUU1FQkFVRUJRa0ZCUWtVRFFzTkZCUVVGQlFVCkZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJUL3dBQVJDQUNXQUdRREFTSUEKQWhFQkF4RUIvOFFBSHdBQUFRVUJBUUVCQVFFQUFBQUFBQUFBQUFFQ0F3UUZCZ2NJQ1FvTC84UUF0UkFBQWdFREF3SUVBd1VGQkFRQQpBQUY5QVFJREFBUVJCUkloTVVFR0UxRmhCeUp4RkRLQmthRUlJMEt4d1JWUzBmQWtNMkp5Z2drS0ZoY1lHUm9sSmljb0tTbzBOVFkzCk9EazZRMFJGUmtkSVNVcFRWRlZXVjFoWldtTmtaV1puYUdscWMzUjFkbmQ0ZVhxRGhJV0doNGlKaXBLVGxKV1dsNWlabXFLanBLV20KcDZpcHFyS3p0TFcydDdpNXVzTER4TVhHeDhqSnl0TFQxTlhXMTlqWjJ1SGk0K1RsNXVmbzZlcng4dlAwOWZiMytQbjYvOFFBSHdFQQpBd0VCQVFFQkFRRUJBUUFBQUFBQUFBRUNBd1FGQmdjSUNRb0wvOFFBdFJFQUFnRUNCQVFEQkFjRkJBUUFBUUozQUFFQ0F4RUVCU0V4CkJoSkJVUWRoY1JNaU1vRUlGRUtSb2JIQkNTTXpVdkFWWW5MUkNoWWtOT0VsOFJjWUdSb21KeWdwS2pVMk56ZzVPa05FUlVaSFNFbEsKVTFSVlZsZFlXVnBqWkdWbVoyaHBhbk4wZFhaM2VIbDZnb09FaFlhSGlJbUtrcE9VbFphWG1KbWFvcU9rcGFhbnFLbXFzck8wdGJhMwp1TG02d3NQRXhjYkh5TW5LMHRQVTFkYlgyTm5hNHVQazVlYm42T25xOHZQMDlmYjMrUG42LzlvQURBTUJBQUlSQXhFQVB3RDlVNktLCktBQ2lpaWdBb29vb0FLS0thN2hGSlBTZ0NscWVxMnVpMkU5N2V6cGJXc0s3NUpwRGhWWDFyNXUrSW43Ym1qZUVneDA3dy9xMTdiSzIKMXRRdUxkb1lWLzJ0djMyWDhLNWY5b2Y0NVJhOVBQb3R1WWY3RWdrMnFWdUZXVzZrWCtKVi91ci9BQTE4amVLdkRYanJ4QTAxMXBxeQp5MmJmSzBlcGJmM2kvd0M4dTFxK1F4bWEvdlBaMHBXUjlYZ2NubFZoN1NwRSszZkJYN1oxbHJWeTBPcFd0dWpLcXliWTVOdjd0djhBCmxvck44ckwvQU44MTlDZUV2R0dsZU05TkY3cFZ5bHhGOTFnUHZJMzkxcS9HcXgwbnhsNFhhMWt2OU5sbGtzMXVMZUh5bTNOSkRNdisKcjNmM1ZiNXE5dCtDbjdTSGlUNFhhL2VGTk44K084a3Qxa2p1MlpZMlZWMnQ4MzhMZjNhTUxtVTR5NWFrdWFJOFpsWHU4MFljc2o5Ugp0dEZlUmVDZjJtL0JmaVhRWXIyOTFHRFFMb3NVa3N0UWxWWkZJNys0OUQzb3I2Tll1aS90SHpMdzlSYWNwNi9SUlJYWVloUlJSUUFVClVVVUFKMnhYbjN4eDhWbndYOE10YjFKRHRrRVloVnY3clNNSTkzL2oxZWduaXZNLzJpdkM5MTR5K0RIaXJUTE9Qekx5UzA4MkpDZnYKTkd5eUFmOEFqdGM5ZE9WS1hLYlVPWDJzZVk4RzhFL0NqVExTeHRieTVqYTZta1ZadDA3ZVp0WnZtYXVsMXpTTlBhejhsTGVOZHY4QQpzMWphVjR4azhJL0QzUjlRMVM3MHZUbS9zMk9abDFTU1RjMjJOZk1iYXRiMFhqblJkZDhGcjRoRXRxTGRsMnM4Yk50WnYrQmZOWDV5CjhMSGt1ZnA5TEVTNW94UEdQRjJoMnIzRExGdDNWNUw0ODA1YlBUWkxqeTFsamorV1JXL2lWcTlNOFFlTDRkWm04eGI3UWRQaG0zZloKZnRNMGl5WEczNzIzNWR2eTE1LzhTb3ByRHdmcWtseEdxK1hIdWJhMjVXWCs4clZ3VThQVW9WSTh4NjFXdEN0VGxGSExlSGZHK2sydQptSkhNdC9jT0Nja3RuYjdVVjRMYitLNzFwTGsyeXQ1Um1iSHkwVjczMVUrUDlvZnZwUlJSWDM1OElGRkZGQUJSUlJRQW1PS3p0ZWpWCjlIdmxmN3BnZmRqL0FIYTBxWTZCMEtrY1ZFbzNqWWNYeXl1ZUJhbm85dDloOHFXTzFXMlpmSi9mUjd0cS93QjFhODcrS0hoeExQd0sKZFB0YlRiYlNTZEZYNzFlZ2VQTEc4MHk2dTd1M3NKZFRldzgxb2JDR1JZMmtiK0hidStYZHQrN3VyenZ4cUwzeFA0ZFdWRnNZN2J5LwpNbWphL1dPYUZ2bCtWbGJiODFmQU9FcWlsSGwrRS9WY0ZKUGxtcEhtbmh2d2xEcTNodGJON1cydkxleDNSckJPdnpRN20rWmR2OE5ZCnZpVHd1dC9vdDFwYktxd3RENWFyL0N2L0FOalcxOE85U211dkVHcVc5cmEzTVZyWjIvbVhGOHpLMXRKdS93Q1dhdC9FeTBXcWZiOVMKdlBOL2VxdHF6TXYrMS9Ddi9mVmVXK2FWU05OL0VldlY1YWNaTkhnZGpvemVEMGxzSWRJRjFENWpPczdXVEV5WjRMWjc4ZzBWOXNmcwpqL0NQVWIvNFZUWGZqSFRiU2EvdU5WdW50V3VMV01uN0tDRmp4N2ZLMktLOXhZQ3M5ZVkrZi90bkF3OTNrMlByZWlpaXZ1ajh5Q2lpCmlnQW9vb29BS0tLS0FQT3ZpSGF4Mk43YjN3R3d6aG9wVDlQdXRYa0hqKzBzbXRacHJxd3Q1UTN5dDgzM3E5ZCtLdXQyTnJjYU5wTXoKcUwyOWVhU0dQKzhzY2Z6ZitoTFhoM2pmNGVXZXBMRzFwZFh6WEZ4OTIyaWszZk5YeEdZWGhYbjdNKzh5YXE2ZEdNcEhqWGlMeHZZKwpITEc0dDdObGlhVDkzdFgrN1QvZ0g1dmo3eDVwMXUwTHJveTNNYzEvZHQ5MWxWdHl4LzhBQW0yN3E3WFRmMlhiTkcrM2VJN2hwZjR2CnNrYmJWWC9lYXZFLzJwdjJzOUwrQlduemVBL2h1dHN2aVpvOXR4ZHdLclI2V3JmK2hUZitnL2VhcXkvS2FrcFJyVmZkRE1zNXB1TXEKTkxXWDRINmxSdytUR2tjUVNORkdBb0hTaXZ5SStBUC9BQVZJOFFmQ3I0YVdIaGp4RDRmdVBHVnhZdTZXK3BTM3pwTjVKd1ZqbEpCMwpzcExmTi9kMmp0UlgyVmo0TS9YNmlpaXJBS0tLS0FDaWl2UGZpSjhlZmg5OEtMbUsyOFdlTHRMMFc4bFhlbG5QTnVtWmY3M2xybHR2CisxdG9BOUNyejc0cmZIWHdIOEVORy90SHhwNGtzOURoWmN4d3l2dW5sLzY1d3JtUi93RGdLMThEZnRNZjhGU3IrNGl1dEUrRmxwSnAKa0xiby93RGhJTCtQZGNTRC9wakQ5MlAvQUhtM04vc3JYd2hkZUpkYThVYXRlYTU0aHZMbld0V3VOMGpYZW9UTk5NemY3VE5VQWZxago4WWZFSStPSHhxK0ZzL2dUVnhGZmFIL3hNdFdzN3VHUlpMZXh1TFZtVnBGL3ZmZFhidStWcEYzYmE5OWgreTZYR3F3UnJGY05Hdm1UCi93QVRmN3JmM2ErY2ZnL2NMTDhmSWZGVnJHdjlrNnA0VGh1SkdXUGR0YVJZMmpWZjlyNzFlamZIVDR0YWI4S1BBTjk0MjFlR1NLeHMKMWFPM2czZnZMcWIvQUpaeHIvdk4vd0N6ZjNheGhocWJxU3E4dnZIWlBFMUhUalNVdmRQQy93QnZEOXFKdmhQNFpid3o0ZnV2SzhXYQpsR3F3dEg4eldzUDhVMys5L0N2KzF1YitHdnkxdVBNZHByeSttYWU0bWtacEdsYmN6TTMzbVpxNnJ4eDR3MXI0b2VOTlU4WGVJSnZQCjFUVXBtbVpWKzdHdjhNYS83S3I4cTFodzJ2MnE0V1psWHk0L3VzMzhUZjNxN0RqSUxiVG96Q3BmY1dORmF2bE5SUUIvU0xSUlJVQUYKRkZGQUhHZkZ2NGxhWDhIdmgzcmZqRFd2TmZUOUxoOHhvNFYzUEl4WUtpTC9BTHpNcTErRGZqVDRoNnQ4UlBHWGlMeFpyTncwK3FheApmU1RUU00zM1YzZktxLzdLL2RWZjdxMStoSC9CVHI5b3E0c0dzL2hWb2Q1NWZuUnJlYTk1ZjhVYmY2bTNiLzBZMy9iT3Z6QjFDOVd3CnM1R2IrRnBQL1FxamxBZGZOOW84UVJ4L3c3dk1yVzMvQUhWck5odDltcGVZMy9QUGJWeGJqWXpTTjkxZm1xK1VEOWJQMkE5TTFEVy8KMlovRE45cUxMY3pOY1hrTnJLMGZ6UjJjTXpSd3gvN1g4VzJ2ajcvZ294OGNCOFR2aXZINEgwZTQzZUZmQ0ROYnNJMitXZSsvNWJTZgo4Qi8xYS83cmYzcStzOUkrSmtmN012OEF3VHc4SjYxR3l4NnkzaCszaDAxRy9pdnJwV2tWditBN21rLzREWDVQelhFaitaTTdOUGRUCk16YnBHK2FSbSs4emYraFZZRk82VDdSSjlsVCs3KytiKzZ2OTMvZ1ZXRjJvdjkxZnVyVWNLYlY4dFczTXpicEpmN3pWUisyTGM2MU4KQ1A4QVUyc2FyLzIwYi83R3FBdE5ja241UHUwVWprQnVldEZBSDlKVkZGRlpBRll2aTN4UnAvZ3J3MXF1dmF2UDlsMHpUTGFTOHVwcwpaMnh4cnVhdHF2anIvZ3AzOFYwOEMvczVYUGg4TEtMenhWT3RoSE5IS0Y4bU5HV1NSbVg3eksyMVkvbC81NmZlb0EvTG40MmZFbTQrCkp2eE84U2VLcnhuV2JWcjZTNlZXL3dDV2NiTis3ai80REdxci93QUJyeUh4WmRMY1c5cnNiNzF3cXRXOWZYdjJoZm0rV1QrSmE0M3gKRlA4QTZQd3UzeTdoVy84QUhhc0R2cnB0alZSdkoyWFQ3eHY3c0xmK2cxWXZwZjNLeWYzbXJZK0Z1azJ2aWo0a2VHOUwxRnR1bXpYMApjbDgzOTIxai9mVGYrUTQ1S29ENlcvYnErSmJYODN3OStHTnZKNVduK0Q5QnMydkYzZjhBTDVKYXgvSzMvWE9OVi83K05YeW5KdWxYCnpQOEFWYmwycXJmd3JXMTQ4OFpYWHhFOGJhOTRtdmYrUGpXTDZiVUpsYitGWkpHWlkvOEFnUHlyL3VyWE56VHMrNXQxQUVjbDU5bFcKUmxWZmxXc1R3azhzdzFHOE9OczB2RGZ4VlBxQ3pYRUxSd0swczBueXF0VDZaWS8ySnBpVzd5TDVtNW1rWmY3MUFFenNkM0xVVlRlUwpNdDk5RFJWZ2YweVVVVVZ6Z1kzaW54UnBmZ3J3M3FXdmF6ZHg2ZnBPbXdTWFYxY3ljTEhHbzNNMWZqRjhWdmlMcXY3Yy93QzByWjJTCjZoQm9PbTN6U2FicE1kOXVhTzF0MVZtWGNxL2VrazI3bS8ybTIvdzE5Sy84RlN2Mm43ZTN0WXZoRDRldTJudW04dTg4UU5iTnU4dGYKdlEycmY3VGZMSXkvM2ZML0FMMWZudjhBQ09LenYvaTE0Wi90ZldydnducHYyeFpwdGJnaithMVpWM0xJck44djNsVmYrQlZFdmhOYQpLaktwR01qN08rSS83UHZnRWFwNEw4VHA0SHRsMGZ3M0l0bjRtMHV5M0xIY1JySHRhUmxYNXBHVnRzMzk1bDNWOGhmdGFmQStMNFk2Ci93RDJwb051emVEdFkyeldNcXllWXNmOFNydS91c3JmTFgzemZmRi93YkZwUDJyVC9FV21UcnFFZjJYVU50d3NpK1p1K1c0LzNkemYKOTh0L3MxOC9lT3J6U2Izd0g0bCtIMnU2NVlwQmEvNlpvc3ZtTElza01uemVTckx1L3dCWEo4eS83TEwvQUhhK1pvNHF2Q3I3K3g5OQppc0ZoS3RCOG5MSHpQa1pyenovRGxyTi9zeDFzZkRtNmExdC9GV3JLMjM3UHBiV01iZjNaTHFSWWYvUmYyaXVlc2RFdjQ5RG5zR1NNCk9yTXNaOHhmbSthdm83NFZmc2RlTy9GSHdoZTN0L3NHbVgydFhkdnFoKzNUTnUreHJESXNMTXFxMjNkNWtqS3JmZVhhMzNXV3ZxS3QKV25SajdTcExsaWZBd3BUcXk5blRqek0rZHRRdjlza2NLZkxKY2Z2Ry93QjMrSC94Mm9kVXY0N0NGVjNmTlgxWGUvOEFCT3p4SzJycApkUytMZE9VcXZLcFp6Ti83TXRZdmpIOWlmVGZBV2c2ajRpOFplTGI2NnNiVlYvMGJSOVBWWkpHWnRxcnVrWnR2ek45N2JYbkxOTUhLClhMR1Y1Zk05TCt5Y1hHUE5LUHUrcVBtN1E3eFpkMXh0WmwrN3VYK0dyRjFjUjd0ejBsM2FRNlVqUVdFYnhXNVptK1krWTMvQW1xZ3IKeHY4QU16SzFldWVRT2E4WFB5cTJLS2dlZDkzeXEyS0tzRCtuQ3VOK0xueERzZmhOOE12RXZqSFVCdXROR3NaYnhrSC9BQzBaVitWZgorQk50WC9nVmRsWGduN2RYaGU3OFcvc2xmRXl4c2QvMmlQUy90bTJQK0pZSkZtWmYrK1kycm5BL0RYWFBFZDU0ajhSYWhyV28zRWx6CnFWOWNTWFZ4T3pibWtta2JkSXpmN1RNMVZadFVrVmY3ek4vRC9lckprdWxWV2JkOHRReDM3UmZNcXEwemZkLzJhMUExR0xiVzgxbGEKNGtYL0FJREd0VFd0MTluaFdHTDVZVi9oL3ZWaHgzVFB1K2JlMzhUZjNxc1EzUzdmdkx1cFdRN3M5ci9aaitHY2Z4dCtPUGhYd25jZgo4Z3U0dUd1dFJaZitmT0ZmTW0vNzZWZHYvQXEvUXY0SitJWlBFdmcvVVBGRjE1Y0UydGFoY2FoNUMvZGpqWnRzTWEvM1ZXRlkxWC9kCnI0Ni80SjRlTWZEL0FJQytMK3BlSVBFT29XZGpicnBzbW54L2FabGozZWF5N3R1Ny9aajIvd0RBcTVuNG5mR0RXdmhIZDZwNEMwSHgKQnArczIwYzBqV04zYlNlWkg5bFptOHZ6R1g1VmsyL0t5MTRXYVlhdGlveGpUUGZ5bkUwTU5LY3FwK2d1cGVJSVpXVm9HYVZXKzd0Kwphdmp2OXJEOXBQVDViVzY4RjZIYjZmck1kMURKRHF6U1NTSzF1Mjc1VmpaZmwzSzN6ZnhmZDIxODNQOEF0QmZFT1d6azBtNDE2U0NHCmFML1dXMzd0djlwZHkvdzE1eGVYRTNtTXpTYldiK0pmdXRYUGc4bjluVTlwVk9ySFp4N1NuN09nTnV0THQvTWE0dFZhS1RkOTNjeTEKSHFFdXhvMmpadDIzNWxhbS9OdC85bHFuY2RLK3BQbFJmdFVuL1BScUtvbDZLeTVnUDZrcW82bHA5dHFtbjNkamRRclBhWEVaaG5oYgo3cnhzTnJLZndvb3FBUDUxdjJpL2h2RjhIL2poNHk4RTI5eDlwczlGMU9XQzNrSSs5RnkwZTcvYThzaFc5eFhtMGtoMk1lN2ZMUlJRCkJQQ3lydFhiV3JONGowZGRIYTNqMGtyZHRHc1lueU9HL3ZVVVZyRURsZFcxaG5tYU9KZHErOVhORmtTR3lCU01lYS9WNktLVWZpQWYKUGNlZnNWOG5MZkkvOFMxSC9hakxONU1xN20vdkxSUlRBY1pWQzhMVks3a0xMUlJSSUNsUlJSV1FILy9aCg==
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD
Apart from the photo not showing in both cases, I've also noticed that the company name which as set to "Moe's Co" has semi colons between each character in the output files.
Can anyone point advise me as to what I have done wrong ? Any advice would be appreciated.
Thanks in advance.
In the second situation, you've double-encoded the Base64 data. You don't need to use
base64.encodestring
ondata
because the vobject code does this for you upon settingencoding_param = 'b'
. This wasn't obvious until I looked at the source to discover what was happening.As for your first situation with the URL-based approach, I'm yet to see a client (Evolution on Ubuntu, Outlook 2010 on Win 7) work correctly with that in a vCard. Your clients are ignoring the URL, as are mine.
The vCard implementations summary at http://microformats.org/wiki/vcard-implementations gives an idea as to the quirks in different applications, though it isn't complete.