Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sendgrid/helpers/mail/mail.py: 36%

468 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1"""Twilio SendGrid v3/mail/send response body builder""" 

2from .bcc_email import Bcc 

3from .cc_email import Cc 

4from .content import Content 

5from .custom_arg import CustomArg 

6from .dynamic_template_data import DynamicTemplateData 

7from .email import Email 

8from .from_email import From 

9from .header import Header 

10from .mime_type import MimeType 

11from .personalization import Personalization 

12from .reply_to import ReplyTo 

13from .send_at import SendAt 

14from .subject import Subject 

15from .substitution import Substitution 

16from .template_id import TemplateId 

17from .to_email import To 

18 

19 

20class Mail(object): 

21 """Creates the response body for v3/mail/send""" 

22 

23 def __init__( 

24 self, 

25 from_email=None, 

26 to_emails=None, 

27 subject=None, 

28 plain_text_content=None, 

29 html_content=None, 

30 amp_html_content=None, 

31 global_substitutions=None, 

32 is_multiple=False): 

33 """ 

34 Creates the response body for a v3/mail/send API call 

35 

36 :param from_email: The email address of the sender 

37 :type from_email: From, tuple, optional 

38 :param subject: The subject of the email 

39 :type subject: Subject, optional 

40 :param to_emails: The email address of the recipient 

41 :type to_emails: To, str, tuple, list(str), list(tuple), 

42 list(To), optional 

43 :param plain_text_content: The plain text body of the email 

44 :type plain_text_content: string, optional 

45 :param html_content: The html body of the email 

46 :type html_content: string, optional 

47 :param amp_html_content: The amp-html body of the email 

48 :type amp_html_content: string, optional 

49 """ 

50 self._attachments = None 

51 self._categories = None 

52 self._contents = None 

53 self._custom_args = None 

54 self._headers = None 

55 self._personalizations = [] 

56 self._sections = None 

57 self._asm = None 

58 self._batch_id = None 

59 self._from_email = None 

60 self._ip_pool_name = None 

61 self._mail_settings = None 

62 self._reply_to = None 

63 self._send_at = None 

64 self._subject = None 

65 self._template_id = None 

66 self._tracking_settings = None 

67 

68 # Minimum required data to send a single email 

69 if from_email is not None: 69 ↛ 71line 69 didn't jump to line 71, because the condition on line 69 was never false

70 self.from_email = from_email 

71 if to_emails is not None: 71 ↛ 73line 71 didn't jump to line 73, because the condition on line 71 was never false

72 self.add_to(to_emails, global_substitutions, is_multiple) 

73 if subject is not None: 73 ↛ 74line 73 didn't jump to line 74, because the condition on line 73 was never true

74 self.subject = subject 

75 if plain_text_content is not None: 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true

76 self.add_content(plain_text_content, MimeType.text) 

77 if amp_html_content is not None: 77 ↛ 78line 77 didn't jump to line 78, because the condition on line 77 was never true

78 self.add_content(amp_html_content, MimeType.amp) 

79 if html_content is not None: 79 ↛ 80line 79 didn't jump to line 80, because the condition on line 79 was never true

80 self.add_content(html_content, MimeType.html) 

81 

82 def __str__(self): 

83 """A JSON-ready string representation of this Mail object. 

84 

85 :returns: A JSON-ready string representation of this Mail object. 

86 :rtype: string 

87 """ 

88 return str(self.get()) 

89 

90 def _ensure_append(self, new_items, append_to, index=0): 

91 """Ensure an item is appended to a list or create a new empty list 

92 

93 :param new_items: the item(s) to append 

94 :type new_items: list(obj) 

95 :param append_to: the list on which to append the items 

96 :type append_to: list() 

97 :param index: index of the list on which to append the items 

98 :type index: int 

99 """ 

100 append_to = append_to or [] 

101 append_to.insert(index, new_items) 

102 return append_to 

103 

104 def _ensure_insert(self, new_items, insert_to): 

105 """Ensure an item is inserted to a list or create a new empty list 

106 

107 :param new_items: the item(s) to insert 

108 :type new_items: list(obj) 

109 :param insert_to: the list on which to insert the items at index 0 

110 :type insert_to: list() 

111 """ 

112 insert_to = insert_to or [] 

113 insert_to.insert(0, new_items) 

114 return insert_to 

115 

116 def _flatten_dicts(self, dicts): 

117 """Flatten a dict 

118 

119 :param dicts: Flatten a dict 

120 :type dicts: list(dict) 

121 """ 

122 d = dict() 

123 list_of_dicts = [d.get() for d in dicts or []] 

124 return {k: v for d in list_of_dicts for k, v in d.items()} 

125 

126 def _get_or_none(self, from_obj): 

127 """Get the JSON representation of the object, else return None 

128 

129 :param from_obj: Get the JSON representation of the object, 

130 else return None 

131 :type from_obj: obj 

132 """ 

133 return from_obj.get() if from_obj is not None else None 

134 

135 def _set_emails( 

136 self, emails, global_substitutions=None, is_multiple=False, p=0): 

137 """Adds emails to the Personalization object 

138 

139 :param emails: An Email or list of Email objects 

140 :type emails: Email, list(Email) 

141 :param global_substitutions: A dict of substitutions for all recipients 

142 :type global_substitutions: dict 

143 :param is_multiple: Create a new personalization for each recipient 

144 :type is_multiple: bool 

145 :param p: p is the Personalization object or Personalization object 

146 index 

147 :type p: Personalization, integer, optional 

148 """ 

149 # Send multiple emails to multiple recipients 

150 if is_multiple is True: 150 ↛ 151line 150 didn't jump to line 151, because the condition on line 150 was never true

151 if isinstance(emails, list): 

152 for email in emails: 

153 personalization = Personalization() 

154 personalization.add_email(email) 

155 self.add_personalization(personalization) 

156 else: 

157 personalization = Personalization() 

158 personalization.add_email(emails) 

159 self.add_personalization(personalization) 

160 if global_substitutions is not None: 

161 if isinstance(global_substitutions, list): 

162 for substitution in global_substitutions: 

163 for p in self.personalizations: 

164 p.add_substitution(substitution) 

165 else: 

166 for p in self.personalizations: 

167 p.add_substitution(global_substitutions) 

168 else: 

169 try: 

170 personalization = self._personalizations[p] 

171 has_internal_personalization = True 

172 except IndexError: 

173 personalization = Personalization() 

174 has_internal_personalization = False 

175 

176 if isinstance(emails, list): 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true

177 for email in emails: 

178 personalization.add_email(email) 

179 else: 

180 personalization.add_email(emails) 

181 

182 if global_substitutions is not None: 182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true

183 if isinstance(global_substitutions, list): 

184 for substitution in global_substitutions: 

185 personalization.add_substitution(substitution) 

186 else: 

187 personalization.add_substitution(global_substitutions) 

188 

189 if not has_internal_personalization: 189 ↛ exitline 189 didn't return from function '_set_emails', because the condition on line 189 was never false

190 self.add_personalization(personalization, index=p) 

191 

192 @property 

193 def personalizations(self): 

194 """A list of one or more Personalization objects 

195 

196 :rtype: list(Personalization) 

197 """ 

198 return self._personalizations 

199 

200 def add_personalization(self, personalization, index=0): 

201 """Add a Personalization object 

202 

203 :param personalization: Add a Personalization object 

204 :type personalization: Personalization 

205 :param index: The index where to add the Personalization 

206 :type index: int 

207 """ 

208 self._personalizations = self._ensure_append( 

209 personalization, self._personalizations, index) 

210 

211 @property 

212 def to(self): 

213 pass 

214 

215 @to.setter 

216 def to(self, to_emails, global_substitutions=None, is_multiple=False, p=0): 

217 """Adds To objects to the Personalization object 

218 

219 :param to_emails: The email addresses of all recipients 

220 :type to_emails: To, str, tuple, list(str), list(tuple), list(To) 

221 :param global_substitutions: A dict of substitutions for all recipients 

222 :type global_substitutions: dict 

223 :param is_multiple: Create a new personalization for each recipient 

224 :type is_multiple: bool 

225 :param p: p is the Personalization object or Personalization object 

226 index 

227 :type p: Personalization, integer, optional 

228 """ 

229 if isinstance(to_emails, list): 

230 for email in to_emails: 

231 if isinstance(email, str): 

232 email = To(email, None) 

233 if isinstance(email, tuple): 

234 email = To(email[0], email[1]) 

235 self.add_to(email, global_substitutions, is_multiple, p) 

236 else: 

237 if isinstance(to_emails, str): 

238 to_emails = To(to_emails, None) 

239 if isinstance(to_emails, tuple): 

240 to_emails = To(to_emails[0], to_emails[1]) 

241 self.add_to(to_emails, global_substitutions, is_multiple, p) 

242 

243 def add_to( 

244 self, to_email, global_substitutions=None, is_multiple=False, p=0): 

245 """Adds a To object to the Personalization object 

246 

247 :param to_email: A To object 

248 :type to_email: To, str, tuple, list(str), list(tuple), list(To) 

249 :param global_substitutions: A dict of substitutions for all recipients 

250 :type global_substitutions: dict 

251 :param is_multiple: Create a new personalization for each recipient 

252 :type is_multiple: bool 

253 :param p: p is the Personalization object or Personalization object 

254 index 

255 :type p: Personalization, integer, optional 

256 """ 

257 

258 if isinstance(to_email, list): 258 ↛ 259line 258 didn't jump to line 259, because the condition on line 258 was never true

259 for email in to_email: 

260 if isinstance(email, str): 

261 email = To(email, None) 

262 elif isinstance(email, tuple): 

263 email = To(email[0], email[1]) 

264 elif not isinstance(email, Email): 

265 raise ValueError( 

266 'Please use a To/Cc/Bcc, tuple, or a str for a to_email list.' 

267 ) 

268 self._set_emails(email, global_substitutions, is_multiple, p) 

269 else: 

270 if isinstance(to_email, str): 270 ↛ 272line 270 didn't jump to line 272, because the condition on line 270 was never false

271 to_email = To(to_email, None) 

272 if isinstance(to_email, tuple): 272 ↛ 273line 272 didn't jump to line 273, because the condition on line 272 was never true

273 to_email = To(to_email[0], to_email[1]) 

274 if isinstance(to_email, Email): 274 ↛ 276line 274 didn't jump to line 276, because the condition on line 274 was never false

275 p = to_email.personalization 

276 self._set_emails(to_email, global_substitutions, is_multiple, p) 

277 

278 @property 

279 def cc(self): 

280 pass 

281 

282 @cc.setter 

283 def cc(self, cc_emails, global_substitutions=None, is_multiple=False, p=0): 

284 """Adds Cc objects to the Personalization object 

285 

286 :param cc_emails: An Cc or list of Cc objects 

287 :type cc_emails: Cc, list(Cc), tuple 

288 :param global_substitutions: A dict of substitutions for all recipients 

289 :type global_substitutions: dict 

290 :param is_multiple: Create a new personalization for each recipient 

291 :type is_multiple: bool 

292 :param p: p is the Personalization object or Personalization object 

293 index 

294 :type p: Personalization, integer, optional 

295 """ 

296 if isinstance(cc_emails, list): 

297 for email in cc_emails: 

298 if isinstance(email, str): 

299 email = Cc(email, None) 

300 if isinstance(email, tuple): 

301 email = Cc(email[0], email[1]) 

302 self.add_cc(email, global_substitutions, is_multiple, p) 

303 else: 

304 if isinstance(cc_emails, str): 

305 cc_emails = Cc(cc_emails, None) 

306 if isinstance(cc_emails, tuple): 

307 cc_emails = To(cc_emails[0], cc_emails[1]) 

308 self.add_cc(cc_emails, global_substitutions, is_multiple, p) 

309 

310 def add_cc( 

311 self, cc_email, global_substitutions=None, is_multiple=False, p=0): 

312 """Adds a Cc object to the Personalization object 

313 

314 :param to_emails: An Cc object 

315 :type to_emails: Cc 

316 :param global_substitutions: A dict of substitutions for all recipients 

317 :type global_substitutions: dict 

318 :param is_multiple: Create a new personalization for each recipient 

319 :type is_multiple: bool 

320 :param p: p is the Personalization object or Personalization object 

321 index 

322 :type p: Personalization, integer, optional 

323 """ 

324 if isinstance(cc_email, str): 

325 cc_email = Cc(cc_email, None) 

326 if isinstance(cc_email, tuple): 

327 cc_email = Cc(cc_email[0], cc_email[1]) 

328 if isinstance(cc_email, Email): 

329 p = cc_email.personalization 

330 self._set_emails( 

331 cc_email, global_substitutions, is_multiple=is_multiple, p=p) 

332 

333 @property 

334 def bcc(self): 

335 pass 

336 

337 @bcc.setter 

338 def bcc( 

339 self, 

340 bcc_emails, 

341 global_substitutions=None, 

342 is_multiple=False, 

343 p=0): 

344 """Adds Bcc objects to the Personalization object 

345 

346 :param bcc_emails: An Bcc or list of Bcc objects 

347 :type bcc_emails: Bcc, list(Bcc), tuple 

348 :param global_substitutions: A dict of substitutions for all recipients 

349 :type global_substitutions: dict 

350 :param is_multiple: Create a new personalization for each recipient 

351 :type is_multiple: bool 

352 :param p: p is the Personalization object or Personalization object 

353 index 

354 :type p: Personalization, integer, optional 

355 """ 

356 if isinstance(bcc_emails, list): 

357 for email in bcc_emails: 

358 if isinstance(email, str): 

359 email = Bcc(email, None) 

360 if isinstance(email, tuple): 

361 email = Bcc(email[0], email[1]) 

362 self.add_bcc(email, global_substitutions, is_multiple, p) 

363 else: 

364 if isinstance(bcc_emails, str): 

365 bcc_emails = Bcc(bcc_emails, None) 

366 if isinstance(bcc_emails, tuple): 

367 bcc_emails = Bcc(bcc_emails[0], bcc_emails[1]) 

368 self.add_bcc(bcc_emails, global_substitutions, is_multiple, p) 

369 

370 def add_bcc( 

371 self, 

372 bcc_email, 

373 global_substitutions=None, 

374 is_multiple=False, 

375 p=0): 

376 """Adds a Bcc object to the Personalization object 

377 

378 :param to_emails: An Bcc object 

379 :type to_emails: Bcc 

380 :param global_substitutions: A dict of substitutions for all recipients 

381 :type global_substitutions: dict 

382 :param is_multiple: Create a new personalization for each recipient 

383 :type is_multiple: bool 

384 :param p: p is the Personalization object or Personalization object 

385 index 

386 :type p: Personalization, integer, optional 

387 """ 

388 if isinstance(bcc_email, str): 

389 bcc_email = Bcc(bcc_email, None) 

390 if isinstance(bcc_email, tuple): 

391 bcc_email = Bcc(bcc_email[0], bcc_email[1]) 

392 if isinstance(bcc_email, Email): 

393 p = bcc_email.personalization 

394 self._set_emails( 

395 bcc_email, 

396 global_substitutions, 

397 is_multiple=is_multiple, 

398 p=p) 

399 

400 @property 

401 def subject(self): 

402 """The global Subject object 

403 

404 :rtype: Subject 

405 """ 

406 return self._subject 

407 

408 @subject.setter 

409 def subject(self, value): 

410 """The subject of the email(s) 

411 

412 :param value: The subject of the email(s) 

413 :type value: Subject, string 

414 """ 

415 if isinstance(value, Subject): 

416 if value.personalization is not None: 

417 try: 

418 personalization = \ 

419 self._personalizations[value.personalization] 

420 has_internal_personalization = True 

421 except IndexError: 

422 personalization = Personalization() 

423 has_internal_personalization = False 

424 personalization.subject = value.subject 

425 

426 if not has_internal_personalization: 

427 self.add_personalization( 

428 personalization, 

429 index=value.personalization) 

430 else: 

431 self._subject = value 

432 else: 

433 self._subject = Subject(value) 

434 

435 @property 

436 def headers(self): 

437 """A list of global Header objects 

438 

439 :rtype: list(Header) 

440 """ 

441 return self._headers 

442 

443 @property 

444 def header(self): 

445 pass 

446 

447 @header.setter 

448 def header(self, headers): 

449 """Add headers to the email 

450 

451 :param value: A list of Header objects or a dict of header key/values 

452 :type value: Header, list(Header), dict 

453 """ 

454 if isinstance(headers, list): 

455 for h in headers: 

456 self.add_header(h) 

457 else: 

458 self.add_header(headers) 

459 

460 def add_header(self, header): 

461 """Add headers to the email globaly or to a specific Personalization 

462 

463 :param value: A Header object or a dict of header key/values 

464 :type value: Header, dict 

465 """ 

466 if header.personalization is not None: 

467 try: 

468 personalization = \ 

469 self._personalizations[header.personalization] 

470 has_internal_personalization = True 

471 except IndexError: 

472 personalization = Personalization() 

473 has_internal_personalization = False 

474 if isinstance(header, dict): 

475 (k, v) = list(header.items())[0] 

476 personalization.add_header(Header(k, v)) 

477 else: 

478 personalization.add_header(header) 

479 

480 if not has_internal_personalization: 

481 self.add_personalization( 

482 personalization, 

483 index=header.personalization) 

484 else: 

485 if isinstance(header, dict): 

486 (k, v) = list(header.items())[0] 

487 self._headers = self._ensure_append( 

488 Header(k, v), self._headers) 

489 else: 

490 self._headers = self._ensure_append(header, self._headers) 

491 

492 @property 

493 def substitution(self): 

494 pass 

495 

496 @substitution.setter 

497 def substitution(self, substitution): 

498 """Add substitutions to the email 

499 

500 :param value: Add substitutions to the email 

501 :type value: Substitution, list(Substitution) 

502 """ 

503 if isinstance(substitution, list): 

504 for s in substitution: 

505 self.add_substitution(s) 

506 else: 

507 self.add_substitution(substitution) 

508 

509 def add_substitution(self, substitution): 

510 """Add a substitution to the email 

511 

512 :param value: Add a substitution to the email 

513 :type value: Substitution 

514 """ 

515 if substitution.personalization: 

516 try: 

517 personalization = \ 

518 self._personalizations[substitution.personalization] 

519 has_internal_personalization = True 

520 except IndexError: 

521 personalization = Personalization() 

522 has_internal_personalization = False 

523 personalization.add_substitution(substitution) 

524 

525 if not has_internal_personalization: 

526 self.add_personalization( 

527 personalization, index=substitution.personalization) 

528 else: 

529 if isinstance(substitution, list): 

530 for s in substitution: 

531 for p in self.personalizations: 

532 p.add_substitution(s) 

533 else: 

534 for p in self.personalizations: 

535 p.add_substitution(substitution) 

536 

537 @property 

538 def custom_args(self): 

539 """A list of global CustomArg objects 

540 

541 :rtype: list(CustomArg) 

542 """ 

543 return self._custom_args 

544 

545 @property 

546 def custom_arg(self): 

547 return self._custom_args 

548 

549 @custom_arg.setter 

550 def custom_arg(self, custom_arg): 

551 """Add custom args to the email 

552 

553 :param value: A list of CustomArg objects or a dict of custom arg 

554 key/values 

555 :type value: CustomArg, list(CustomArg), dict 

556 """ 

557 if isinstance(custom_arg, list): 

558 for c in custom_arg: 

559 self.add_custom_arg(c) 

560 else: 

561 self.add_custom_arg(custom_arg) 

562 

563 def add_custom_arg(self, custom_arg): 

564 """Add custom args to the email globaly or to a specific Personalization 

565 

566 :param value: A CustomArg object or a dict of custom arg key/values 

567 :type value: CustomArg, dict 

568 """ 

569 if custom_arg.personalization is not None: 

570 try: 

571 personalization = \ 

572 self._personalizations[custom_arg.personalization] 

573 has_internal_personalization = True 

574 except IndexError: 

575 personalization = Personalization() 

576 has_internal_personalization = False 

577 if isinstance(custom_arg, dict): 

578 (k, v) = list(custom_arg.items())[0] 

579 personalization.add_custom_arg(CustomArg(k, v)) 

580 else: 

581 personalization.add_custom_arg(custom_arg) 

582 

583 if not has_internal_personalization: 

584 self.add_personalization( 

585 personalization, index=custom_arg.personalization) 

586 else: 

587 if isinstance(custom_arg, dict): 

588 (k, v) = list(custom_arg.items())[0] 

589 self._custom_args = self._ensure_append( 

590 CustomArg(k, v), self._custom_args) 

591 else: 

592 self._custom_args = self._ensure_append( 

593 custom_arg, self._custom_args) 

594 

595 @property 

596 def send_at(self): 

597 """The global SendAt object 

598 

599 :rtype: SendAt 

600 """ 

601 return self._send_at 

602 

603 @send_at.setter 

604 def send_at(self, value): 

605 """A unix timestamp specifying when your email should 

606 be delivered. 

607 

608 :param value: A unix timestamp specifying when your email should 

609 be delivered. 

610 :type value: SendAt, int 

611 """ 

612 if isinstance(value, SendAt): 

613 if value.personalization is not None: 

614 try: 

615 personalization = \ 

616 self._personalizations[value.personalization] 

617 has_internal_personalization = True 

618 except IndexError: 

619 personalization = Personalization() 

620 has_internal_personalization = False 

621 personalization.send_at = value.send_at 

622 

623 if not has_internal_personalization: 

624 self.add_personalization( 

625 personalization, index=value.personalization) 

626 else: 

627 self._send_at = value 

628 else: 

629 self._send_at = SendAt(value) 

630 

631 @property 

632 def dynamic_template_data(self): 

633 pass 

634 

635 @dynamic_template_data.setter 

636 def dynamic_template_data(self, value): 

637 """Data for a transactional template 

638 

639 :param value: Data for a transactional template 

640 :type value: DynamicTemplateData, a JSON-serializable structure 

641 """ 

642 if not isinstance(value, DynamicTemplateData): 642 ↛ 644line 642 didn't jump to line 644, because the condition on line 642 was never false

643 value = DynamicTemplateData(value) 

644 try: 

645 personalization = self._personalizations[value.personalization] 

646 has_internal_personalization = True 

647 except IndexError: 

648 personalization = Personalization() 

649 has_internal_personalization = False 

650 personalization.dynamic_template_data = value.dynamic_template_data 

651 

652 if not has_internal_personalization: 652 ↛ 653line 652 didn't jump to line 653, because the condition on line 652 was never true

653 self.add_personalization( 

654 personalization, index=value.personalization) 

655 

656 @property 

657 def from_email(self): 

658 """The email address of the sender 

659 

660 :rtype: From 

661 """ 

662 return self._from_email 

663 

664 @from_email.setter 

665 def from_email(self, value): 

666 """The email address of the sender 

667 

668 :param value: The email address of the sender 

669 :type value: From, str, tuple 

670 """ 

671 if isinstance(value, str): 671 ↛ 673line 671 didn't jump to line 673, because the condition on line 671 was never false

672 value = From(value, None) 

673 if isinstance(value, tuple): 673 ↛ 674line 673 didn't jump to line 674, because the condition on line 673 was never true

674 value = From(value[0], value[1]) 

675 self._from_email = value 

676 

677 @property 

678 def reply_to(self): 

679 """The reply to email address 

680 

681 :rtype: ReplyTo 

682 """ 

683 return self._reply_to 

684 

685 @reply_to.setter 

686 def reply_to(self, value): 

687 """The reply to email address 

688 

689 :param value: The reply to email address 

690 :type value: ReplyTo, str, tuple 

691 """ 

692 if isinstance(value, str): 

693 value = ReplyTo(value, None) 

694 if isinstance(value, tuple): 

695 value = ReplyTo(value[0], value[1]) 

696 self._reply_to = value 

697 

698 @property 

699 def contents(self): 

700 """The contents of the email 

701 

702 :rtype: list(Content) 

703 """ 

704 return self._contents 

705 

706 @property 

707 def content(self): 

708 pass 

709 

710 @content.setter 

711 def content(self, contents): 

712 """The content(s) of the email 

713 

714 :param contents: The content(s) of the email 

715 :type contents: Content, list(Content) 

716 """ 

717 if isinstance(contents, list): 

718 for c in contents: 

719 self.add_content(c) 

720 else: 

721 self.add_content(contents) 

722 

723 def add_content(self, content, mime_type=None): 

724 """Add content to the email 

725 

726 :param contents: Content to be added to the email 

727 :type contents: Content 

728 :param mime_type: Override the mime type 

729 :type mime_type: MimeType, str 

730 """ 

731 if isinstance(content, str): 

732 content = Content(mime_type, content) 

733 # Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html 

734 if content.mime_type == MimeType.text: 

735 self._contents = self._ensure_insert(content, self._contents) 

736 elif content.mime_type == MimeType.amp: 

737 if self._contents: 

738 for _content in self._contents: 

739 # this is written in the context that plain text content will always come earlier than the html content 

740 if _content.mime_type == MimeType.text: 

741 index = 1 

742 break 

743 elif _content.mime_type == MimeType.html: 

744 index = 0 

745 break 

746 else: 

747 index = 0 

748 self._contents = self._ensure_append( 

749 content, self._contents, index=index) 

750 else: 

751 if self._contents: 

752 index = len(self._contents) 

753 else: 

754 index = 0 

755 self._contents = self._ensure_append( 

756 content, self._contents, index=index) 

757 

758 @property 

759 def attachments(self): 

760 """The attachments to this email 

761 

762 :rtype: list(Attachment) 

763 """ 

764 return self._attachments 

765 

766 @property 

767 def attachment(self): 

768 pass 

769 

770 @attachment.setter 

771 def attachment(self, attachment): 

772 """Add attachment(s) to this email 

773 

774 :param attachment: Add attachment(s) to this email 

775 :type attachment: Attachment, list(Attachment) 

776 """ 

777 if isinstance(attachment, list): 

778 for a in attachment: 

779 self.add_attachment(a) 

780 else: 

781 self.add_attachment(attachment) 

782 

783 def add_attachment(self, attachment): 

784 """Add an attachment to this email 

785 

786 :param attachment: Add an attachment to this email 

787 :type attachment: Attachment 

788 """ 

789 self._attachments = self._ensure_append(attachment, self._attachments) 

790 

791 @property 

792 def template_id(self): 

793 """The transactional template id for this email 

794 

795 :rtype: TemplateId 

796 """ 

797 return self._template_id 

798 

799 @template_id.setter 

800 def template_id(self, value): 

801 """The transactional template id for this email 

802 

803 :param value: The transactional template id for this email 

804 :type value: TemplateId 

805 """ 

806 if isinstance(value, TemplateId): 806 ↛ 807line 806 didn't jump to line 807, because the condition on line 806 was never true

807 self._template_id = value 

808 else: 

809 self._template_id = TemplateId(value) 

810 

811 @property 

812 def sections(self): 

813 """The block sections of code to be used as substitutions 

814 

815 :rtype: Section 

816 """ 

817 return self._sections 

818 

819 @property 

820 def section(self): 

821 pass 

822 

823 @section.setter 

824 def section(self, section): 

825 """The block sections of code to be used as substitutions 

826 

827 :rtype: Section, list(Section) 

828 """ 

829 if isinstance(section, list): 

830 for h in section: 

831 self.add_section(h) 

832 else: 

833 self.add_section(section) 

834 

835 def add_section(self, section): 

836 """A block section of code to be used as substitutions 

837 

838 :param section: A block section of code to be used as substitutions 

839 :type section: Section 

840 """ 

841 self._sections = self._ensure_append(section, self._sections) 

842 

843 @property 

844 def categories(self): 

845 """The categories assigned to this message 

846 

847 :rtype: list(Category) 

848 """ 

849 return self._categories 

850 

851 @property 

852 def category(self): 

853 pass 

854 

855 @category.setter 

856 def category(self, categories): 

857 """Add categories assigned to this message 

858 

859 :rtype: list(Category) 

860 """ 

861 if isinstance(categories, list): 

862 for c in categories: 

863 self.add_category(c) 

864 else: 

865 self.add_category(categories) 

866 

867 def add_category(self, category): 

868 """Add a category assigned to this message 

869 

870 :rtype: Category 

871 """ 

872 self._categories = self._ensure_append(category, self._categories) 

873 

874 @property 

875 def batch_id(self): 

876 """The batch id for this email 

877 

878 :rtype: BatchId 

879 """ 

880 return self._batch_id 

881 

882 @batch_id.setter 

883 def batch_id(self, value): 

884 """The batch id for this email 

885 

886 :param value: The batch id for this email 

887 :type value: BatchId 

888 """ 

889 self._batch_id = value 

890 

891 @property 

892 def asm(self): 

893 """An object specifying unsubscribe behavior. 

894 

895 :rtype: Asm 

896 """ 

897 return self._asm 

898 

899 @asm.setter 

900 def asm(self, value): 

901 """An object specifying unsubscribe behavior. 

902 

903 :param value: An object specifying unsubscribe behavior. 

904 :type value: Asm 

905 """ 

906 self._asm = value 

907 

908 @property 

909 def ip_pool_name(self): 

910 """The IP Pool that you would like to send this email from 

911 

912 :rtype: IpPoolName 

913 """ 

914 return self._ip_pool_name 

915 

916 @ip_pool_name.setter 

917 def ip_pool_name(self, value): 

918 """The IP Pool that you would like to send this email from 

919 

920 :paran value: The IP Pool that you would like to send this email from 

921 :type value: IpPoolName 

922 """ 

923 self._ip_pool_name = value 

924 

925 @property 

926 def mail_settings(self): 

927 """The mail settings for this email 

928 

929 :rtype: MailSettings 

930 """ 

931 return self._mail_settings 

932 

933 @mail_settings.setter 

934 def mail_settings(self, value): 

935 """The mail settings for this email 

936 

937 :param value: The mail settings for this email 

938 :type value: MailSettings 

939 """ 

940 self._mail_settings = value 

941 

942 @property 

943 def tracking_settings(self): 

944 """The tracking settings for this email 

945 

946 :rtype: TrackingSettings 

947 """ 

948 return self._tracking_settings 

949 

950 @tracking_settings.setter 

951 def tracking_settings(self, value): 

952 """The tracking settings for this email 

953 

954 :param value: The tracking settings for this email 

955 :type value: TrackingSettings 

956 """ 

957 self._tracking_settings = value 

958 

959 def get(self): 

960 """ 

961 Get a JSON-ready representation of this Mail object. 

962 

963 :returns: This Mail object, ready for use in a request body. 

964 :rtype: dict 

965 """ 

966 mail = { 

967 'from': self._get_or_none(self.from_email), 

968 'subject': self._get_or_none(self.subject), 

969 'personalizations': [p.get() for p in self.personalizations or []], 

970 'content': [c.get() for c in self.contents or []], 

971 'attachments': [a.get() for a in self.attachments or []], 

972 'template_id': self._get_or_none(self.template_id), 

973 'sections': self._flatten_dicts(self.sections), 

974 'headers': self._flatten_dicts(self.headers), 

975 'categories': [c.get() for c in self.categories or []], 

976 'custom_args': self._flatten_dicts(self.custom_args), 

977 'send_at': self._get_or_none(self.send_at), 

978 'batch_id': self._get_or_none(self.batch_id), 

979 'asm': self._get_or_none(self.asm), 

980 'ip_pool_name': self._get_or_none(self.ip_pool_name), 

981 'mail_settings': self._get_or_none(self.mail_settings), 

982 'tracking_settings': self._get_or_none(self.tracking_settings), 

983 'reply_to': self._get_or_none(self.reply_to), 

984 } 

985 

986 return {key: value for key, value in mail.items() 

987 if value is not None and value != [] and value != {}} 

988 

989 @classmethod 

990 def from_EmailMessage(cls, message): 

991 """Create a Mail object from an instance of 

992 email.message.EmailMessage. 

993 

994 :type message: email.message.EmailMessage 

995 :rtype: Mail 

996 """ 

997 mail = cls( 

998 from_email=Email(message.get('From')), 

999 subject=message.get('Subject'), 

1000 to_emails=Email(message.get('To')), 

1001 ) 

1002 try: 

1003 body = message.get_content() 

1004 except AttributeError: 

1005 # Python2 

1006 body = message.get_payload() 

1007 mail.add_content(Content( 

1008 message.get_content_type(), 

1009 body.strip() 

1010 )) 

1011 for k, v in message.items(): 

1012 mail.add_header(Header(k, v)) 

1013 return mail