1 # portage.py -- core Portage functionality
2 # Copyright 1998-2004 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
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
15 from portage import os
16 from portage import _encodings
17 from portage import _unicode_encode
18 from portage.localization import _
21 if sys.hexversion >= 0x3000000:
24 if sys.hexversion >= 0x3000000:
25 def TextMessage(_text):
26 return MIMEText(_text, _charset="UTF-8")
28 TextMessage = MIMEText
30 def create_message(sender, recipient, subject, body, attachments=None):
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')
42 if attachments == None:
43 mymessage = TextMessage(body)
45 mymessage = MultipartMessage()
46 mymessage.attach(TextMessage(body))
48 if isinstance(x, BaseMessage):
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))
57 raise portage.exception.PortageException(_("Can't handle type of attachment: %s") % type(x))
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")
69 def send_mail(mysettings, message):
70 mymailhost = "localhost"
74 myrecipient = "root@localhost"
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()
87 myauthdata, myconndata = mymailuri.rsplit("@", 1)
89 mymailuser,mymailpasswd = myauthdata.split(":")
91 print(_("!!! invalid SMTP AUTH configuration, trying unauthenticated ..."))
93 myconndata = mymailuri
95 mymailhost,mymailport = myconndata.split(":")
97 mymailhost = myconndata
99 myrecipient = mysettings["PORTAGE_ELOG_MAILURI"]
101 myfrom = message.get("From")
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')
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)
125 if int(mymailport) > 100000:
126 myconn = smtplib.SMTP(mymailhost, int(mymailport) - 100000)
128 if not myconn.has_extn("STARTTLS"):
129 raise portage.exception.PortageException(_("!!! TLS support requested for logmail but not suported by server"))
133 myconn = smtplib.SMTP(mymailhost, mymailport)
134 if mymailuser != "" and mymailpasswd != "":
135 myconn.login(mymailuser, mymailpasswd)
136 myconn.sendmail(myfrom, myrecipient, message.as_string())
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))