Convert MIMEText body to string before sending. (trunk r14808)
[portage.git] / pym / portage / mail.py
1 # portage.py -- core Portage functionality
2 # Copyright 1998-2004 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Id$
5
6 from email.mime.text import MIMEText
7 from email.mime.multipart import MIMEMultipart as MultipartMessage
8 from email.mime.base import MIMEBase as BaseMessage
9 from email.header import Header
10 import smtplib
11 import socket
12 import sys
13 import time
14
15 from portage import os
16 from portage import _encodings
17 from portage import _unicode_encode
18 from portage.localization import _
19 import portage
20
21 if sys.hexversion >= 0x3000000:
22         basestring = str
23
24 if sys.hexversion >= 0x3000000:
25         def TextMessage(_text):
26                 return MIMEText(_text, _charset="UTF-8")
27 else:
28         TextMessage = MIMEText
29
30 def create_message(sender, recipient, subject, body, attachments=None):
31
32         if sys.hexversion < 0x3000000:
33                 sender = _unicode_encode(sender,
34                         encoding=_encodings['content'], errors='strict')
35                 recipient = _unicode_encode(recipient,
36                         encoding=_encodings['content'], errors='strict')
37                 subject = _unicode_encode(subject,
38                         encoding=_encodings['content'], errors='backslashreplace')
39                 body = _unicode_encode(body,
40                         encoding=_encodings['content'], errors='backslashreplace')
41
42         if attachments == None:
43                 mymessage = TextMessage(body)
44         else:
45                 mymessage = MultipartMessage()
46                 mymessage.attach(TextMessage(body))
47                 for x in attachments:
48                         if isinstance(x, BaseMessage):
49                                 mymessage.attach(x)
50                         elif isinstance(x, basestring):
51                                 if sys.hexversion < 0x3000000:
52                                         x = _unicode_encode(x,
53                                                 encoding=_encodings['content'],
54                                                 errors='backslashreplace')
55                                 mymessage.attach(TextMessage(x))
56                         else:
57                                 raise portage.exception.PortageException(_("Can't handle type of attachment: %s") % type(x))
58
59         mymessage.set_unixfrom(sender)
60         mymessage["To"] = recipient
61         mymessage["From"] = sender
62         # Use Header as a workaround so that long subject lines are wrapped
63         # correctly by <=python-2.6 (gentoo bug #263370, python issue #1974).
64         mymessage["Subject"] = Header(subject)
65         mymessage["Date"] = time.strftime("%a, %d %b %Y %H:%M:%S %z")
66         
67         return mymessage
68
69 def send_mail(mysettings, message):
70         mymailhost = "localhost"
71         mymailport = 25
72         mymailuser = ""
73         mymailpasswd = ""
74         myrecipient = "root@localhost"
75         
76         # Syntax for PORTAGE_ELOG_MAILURI (if defined):
77         # adress [[user:passwd@]mailserver[:port]]
78         # where adress:     recipient adress
79         #       user:       username for smtp auth (defaults to none)
80         #       passwd:     password for smtp auth (defaults to none)
81         #       mailserver: smtp server that should be used to deliver the mail (defaults to localhost)
82         #                                       alternatively this can also be the absolute path to a sendmail binary if you don't want to use smtp
83         #       port:       port to use on the given smtp server (defaults to 25, values > 100000 indicate that starttls should be used on (port-100000))
84         if " " in mysettings["PORTAGE_ELOG_MAILURI"]:
85                 myrecipient, mymailuri = mysettings["PORTAGE_ELOG_MAILURI"].split()
86                 if "@" in mymailuri:
87                         myauthdata, myconndata = mymailuri.rsplit("@", 1)
88                         try:
89                                 mymailuser,mymailpasswd = myauthdata.split(":")
90                         except ValueError:
91                                 print(_("!!! invalid SMTP AUTH configuration, trying unauthenticated ..."))
92                 else:
93                         myconndata = mymailuri
94                 if ":" in myconndata:
95                         mymailhost,mymailport = myconndata.split(":")
96                 else:
97                         mymailhost = myconndata
98         else:
99                 myrecipient = mysettings["PORTAGE_ELOG_MAILURI"]
100         
101         myfrom = message.get("From")
102
103         if sys.hexversion < 0x3000000:
104                 myrecipient = _unicode_encode(myrecipient,
105                         encoding=_encodings['content'], errors='strict')
106                 mymailhost = _unicode_encode(mymailhost,
107                         encoding=_encodings['content'], errors='strict')
108                 mymailport = _unicode_encode(mymailport,
109                         encoding=_encodings['content'], errors='strict')
110                 myfrom = _unicode_encode(myfrom,
111                         encoding=_encodings['content'], errors='strict')
112                 mymailuser = _unicode_encode(mymailuser,
113                         encoding=_encodings['content'], errors='strict')
114                 mymailpasswd = _unicode_encode(mymailpasswd,
115                         encoding=_encodings['content'], errors='strict')
116
117         # user wants to use a sendmail binary instead of smtp
118         if mymailhost[0] == os.sep and os.path.exists(mymailhost):
119                 fd = os.popen(mymailhost+" -f "+myfrom+" "+myrecipient, "w")
120                 fd.write(message.as_string())
121                 if fd.close() != None:
122                         sys.stderr.write(_("!!! %s returned with a non-zero exit code. This generally indicates an error.\n") % mymailhost)
123         else:
124                 try:
125                         if int(mymailport) > 100000:
126                                 myconn = smtplib.SMTP(mymailhost, int(mymailport) - 100000)
127                                 myconn.ehlo()
128                                 if not myconn.has_extn("STARTTLS"):
129                                         raise portage.exception.PortageException(_("!!! TLS support requested for logmail but not suported by server"))
130                                 myconn.starttls()
131                                 myconn.ehlo()
132                         else:
133                                 myconn = smtplib.SMTP(mymailhost, mymailport)
134                         if mymailuser != "" and mymailpasswd != "":
135                                 myconn.login(mymailuser, mymailpasswd)
136                         myconn.sendmail(myfrom, myrecipient, message.as_string())
137                         myconn.quit()
138                 except smtplib.SMTPException as e:
139                         raise portage.exception.PortageException(_("!!! An error occured while trying to send logmail:\n")+str(e))
140                 except socket.error as e:
141                         raise portage.exception.PortageException(_("!!! A network error occured while trying to send logmail:\n%s\nSure you configured PORTAGE_ELOG_MAILURI correctly?") % str(e))
142         return
143