22 |
23 |
24 |
25 |
26 |
27 |
Secure .NET email library and proxy with full support for SMTP, IMAP, POP3, and S/MIME. Free and open source.
28 |
29 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/OpaqueMail.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bertjohnson/OpaqueMail/63d55f213a0dd6cf91ddd44e00b63526b083ac17/OpaqueMail.nupkg
--------------------------------------------------------------------------------
/OpaqueMail.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail", "OpaqueMail\OpaqueMail.csproj", "{BF21D27F-72AD-492E-8219-6C82C2330C72}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail.TestClient", "OpaqueMail.TestClient\OpaqueMail.TestClient.csproj", "{C1BC8A46-7219-4831-A917-2BD87CF8D972}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1E3374C3-7C9B-4FAA-B1C6-B3609E903428}"
11 | ProjectSection(SolutionItems) = preProject
12 | CHANGELOG.md = CHANGELOG.md
13 | LICENSE.md = LICENSE.md
14 | OpaqueMail.doxygen = OpaqueMail.doxygen
15 | OpaqueMail.doxygen.header.html = OpaqueMail.doxygen.header.html
16 | OpaqueMail.nupkg = OpaqueMail.nupkg
17 | README.md = README.md
18 | EndProjectSection
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail.CertHelper", "OpaqueMail.CertHelper\OpaqueMail.CertHelper.csproj", "{9F1402F2-D701-43A5-9AD6-CFA926C31DCE}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail.Proxy", "OpaqueMail.Proxy\OpaqueMail.Proxy.csproj", "{FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}"
23 | EndProject
24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail.ProxyService", "OpaqueMail.ProxyService\OpaqueMail.ProxyService.csproj", "{C8F12621-2E22-48FD-8E52-71F1B059179E}"
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpaqueMail.ProxySettings", "OpaqueMail.ProxySettings\OpaqueMail.ProxySettings.csproj", "{EE9F6184-F918-4FC0-9018-3019DFB8A408}"
27 | EndProject
28 | Global
29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
30 | CD_ROM|Any CPU = CD_ROM|Any CPU
31 | CD_ROM|ARM = CD_ROM|ARM
32 | CD_ROM|x64 = CD_ROM|x64
33 | CD_ROM|x86 = CD_ROM|x86
34 | Debug|Any CPU = Debug|Any CPU
35 | Debug|ARM = Debug|ARM
36 | Debug|x64 = Debug|x64
37 | Debug|x86 = Debug|x86
38 | DVD-5|Any CPU = DVD-5|Any CPU
39 | DVD-5|ARM = DVD-5|ARM
40 | DVD-5|x64 = DVD-5|x64
41 | DVD-5|x86 = DVD-5|x86
42 | Release|Any CPU = Release|Any CPU
43 | Release|ARM = Release|ARM
44 | Release|x64 = Release|x64
45 | Release|x86 = Release|x86
46 | SingleImage|Any CPU = SingleImage|Any CPU
47 | SingleImage|ARM = SingleImage|ARM
48 | SingleImage|x64 = SingleImage|x64
49 | SingleImage|x86 = SingleImage|x86
50 | EndGlobalSection
51 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
52 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
53 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
54 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
55 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.CD_ROM|x64.ActiveCfg = Release|Any CPU
56 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.CD_ROM|x86.ActiveCfg = Release|Any CPU
57 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Debug|ARM.ActiveCfg = Debug|Any CPU
60 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Debug|x64.ActiveCfg = Debug|Any CPU
61 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Debug|x86.ActiveCfg = Debug|Any CPU
62 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
63 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
64 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
65 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.DVD-5|x64.ActiveCfg = Debug|Any CPU
66 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.DVD-5|x86.ActiveCfg = Debug|Any CPU
67 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Release|Any CPU.Build.0 = Release|Any CPU
69 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Release|ARM.ActiveCfg = Release|Any CPU
70 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Release|x64.ActiveCfg = Release|Any CPU
71 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.Release|x86.ActiveCfg = Release|Any CPU
72 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
73 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.SingleImage|Any CPU.Build.0 = Release|Any CPU
74 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.SingleImage|ARM.ActiveCfg = Release|Any CPU
75 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.SingleImage|x64.ActiveCfg = Release|Any CPU
76 | {BF21D27F-72AD-492E-8219-6C82C2330C72}.SingleImage|x86.ActiveCfg = Release|Any CPU
77 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
78 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
79 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
80 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.CD_ROM|x64.ActiveCfg = Release|Any CPU
81 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.CD_ROM|x86.ActiveCfg = Release|Any CPU
82 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
83 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Debug|Any CPU.Build.0 = Debug|Any CPU
84 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Debug|ARM.ActiveCfg = Debug|Any CPU
85 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Debug|x64.ActiveCfg = Debug|Any CPU
86 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Debug|x86.ActiveCfg = Debug|Any CPU
87 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
88 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
89 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
90 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.DVD-5|x64.ActiveCfg = Debug|Any CPU
91 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.DVD-5|x86.ActiveCfg = Debug|Any CPU
92 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Release|Any CPU.ActiveCfg = Release|Any CPU
93 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Release|Any CPU.Build.0 = Release|Any CPU
94 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Release|ARM.ActiveCfg = Release|Any CPU
95 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Release|x64.ActiveCfg = Release|Any CPU
96 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.Release|x86.ActiveCfg = Release|Any CPU
97 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
98 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.SingleImage|Any CPU.Build.0 = Release|Any CPU
99 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.SingleImage|ARM.ActiveCfg = Release|Any CPU
100 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.SingleImage|x64.ActiveCfg = Release|Any CPU
101 | {C1BC8A46-7219-4831-A917-2BD87CF8D972}.SingleImage|x86.ActiveCfg = Release|Any CPU
102 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
103 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
104 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
105 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.CD_ROM|x64.ActiveCfg = Release|Any CPU
106 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.CD_ROM|x86.ActiveCfg = Release|Any CPU
107 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
108 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
109 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Debug|ARM.ActiveCfg = Debug|Any CPU
110 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Debug|x64.ActiveCfg = Debug|Any CPU
111 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Debug|x86.ActiveCfg = Debug|Any CPU
112 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
113 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
114 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
115 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.DVD-5|x64.ActiveCfg = Debug|Any CPU
116 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.DVD-5|x86.ActiveCfg = Debug|Any CPU
117 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
118 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Release|Any CPU.Build.0 = Release|Any CPU
119 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Release|ARM.ActiveCfg = Release|Any CPU
120 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Release|x64.ActiveCfg = Release|Any CPU
121 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.Release|x86.ActiveCfg = Release|Any CPU
122 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
123 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.SingleImage|Any CPU.Build.0 = Release|Any CPU
124 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.SingleImage|ARM.ActiveCfg = Release|Any CPU
125 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.SingleImage|x64.ActiveCfg = Release|Any CPU
126 | {9F1402F2-D701-43A5-9AD6-CFA926C31DCE}.SingleImage|x86.ActiveCfg = Release|Any CPU
127 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
128 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
129 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
130 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.CD_ROM|x64.ActiveCfg = Release|Any CPU
131 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.CD_ROM|x86.ActiveCfg = Release|Any CPU
132 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
133 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
134 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Debug|ARM.ActiveCfg = Debug|Any CPU
135 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Debug|x64.ActiveCfg = Debug|Any CPU
136 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Debug|x86.ActiveCfg = Debug|Any CPU
137 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
138 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
139 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
140 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.DVD-5|x64.ActiveCfg = Debug|Any CPU
141 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.DVD-5|x86.ActiveCfg = Debug|Any CPU
142 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
143 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Release|Any CPU.Build.0 = Release|Any CPU
144 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Release|ARM.ActiveCfg = Release|Any CPU
145 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Release|x64.ActiveCfg = Release|Any CPU
146 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.Release|x86.ActiveCfg = Release|Any CPU
147 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
148 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.SingleImage|Any CPU.Build.0 = Release|Any CPU
149 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.SingleImage|ARM.ActiveCfg = Release|Any CPU
150 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.SingleImage|x64.ActiveCfg = Release|Any CPU
151 | {FBDCF97D-7EF1-470D-A13F-04CAB5911D6B}.SingleImage|x86.ActiveCfg = Release|Any CPU
152 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
153 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
154 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
155 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.CD_ROM|x64.ActiveCfg = Release|Any CPU
156 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.CD_ROM|x86.ActiveCfg = Release|Any CPU
157 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
158 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Debug|Any CPU.Build.0 = Debug|Any CPU
159 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Debug|ARM.ActiveCfg = Debug|Any CPU
160 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Debug|x64.ActiveCfg = Debug|Any CPU
161 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Debug|x86.ActiveCfg = Debug|Any CPU
162 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
163 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
164 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
165 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.DVD-5|x64.ActiveCfg = Debug|Any CPU
166 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.DVD-5|x86.ActiveCfg = Debug|Any CPU
167 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Release|Any CPU.ActiveCfg = Release|Any CPU
168 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Release|Any CPU.Build.0 = Release|Any CPU
169 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Release|ARM.ActiveCfg = Release|Any CPU
170 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Release|x64.ActiveCfg = Release|Any CPU
171 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.Release|x86.ActiveCfg = Release|Any CPU
172 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
173 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.SingleImage|Any CPU.Build.0 = Release|Any CPU
174 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.SingleImage|ARM.ActiveCfg = Release|Any CPU
175 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.SingleImage|x64.ActiveCfg = Release|Any CPU
176 | {C8F12621-2E22-48FD-8E52-71F1B059179E}.SingleImage|x86.ActiveCfg = Release|Any CPU
177 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
178 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
179 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.CD_ROM|ARM.ActiveCfg = Release|Any CPU
180 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.CD_ROM|x64.ActiveCfg = Release|Any CPU
181 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.CD_ROM|x86.ActiveCfg = Release|Any CPU
182 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
183 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Debug|Any CPU.Build.0 = Debug|Any CPU
184 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Debug|ARM.ActiveCfg = Debug|Any CPU
185 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Debug|x64.ActiveCfg = Debug|Any CPU
186 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Debug|x86.ActiveCfg = Debug|Any CPU
187 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
188 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
189 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.DVD-5|ARM.ActiveCfg = Debug|Any CPU
190 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.DVD-5|x64.ActiveCfg = Debug|Any CPU
191 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.DVD-5|x86.ActiveCfg = Debug|Any CPU
192 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Release|Any CPU.ActiveCfg = Release|Any CPU
193 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Release|Any CPU.Build.0 = Release|Any CPU
194 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Release|ARM.ActiveCfg = Release|Any CPU
195 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Release|x64.ActiveCfg = Release|Any CPU
196 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.Release|x86.ActiveCfg = Release|Any CPU
197 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
198 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.SingleImage|Any CPU.Build.0 = Release|Any CPU
199 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.SingleImage|ARM.ActiveCfg = Release|Any CPU
200 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.SingleImage|x64.ActiveCfg = Release|Any CPU
201 | {EE9F6184-F918-4FC0-9018-3019DFB8A408}.SingleImage|x86.ActiveCfg = Release|Any CPU
202 | EndGlobalSection
203 | GlobalSection(SolutionProperties) = preSolution
204 | HideSolutionNode = FALSE
205 | EndGlobalSection
206 | EndGlobal
207 |
--------------------------------------------------------------------------------
/OpaqueMail/AlternateView.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System.Collections.ObjectModel;
17 | using System.IO;
18 | using System.Text;
19 |
20 | namespace OpaqueMail
21 | {
22 | ///
Represents the format to view an email message.
23 | public class AlternateView : Attachment
24 | {
25 | #region Public Members
26 | public TransferEncoding TransferEncoding { get; set; }
27 | #endregion Public Members
28 |
29 | #region Constructors
30 | public AlternateView() : base()
31 | {
32 | }
33 |
34 | ///
Initializes a new instance of with the specified file name.
35 | ///
The name of the file that contains the content for this alternate view.
36 | ///
37 | /// is null.
38 | ///
The caller does not have the required permission.
39 | ///
An I/O error occurred, such as a disk error.
40 | ///
The access requested is not permitted by the operating system for the specified file handle, such as when access is Write or ReadWrite and the file handle is set for read-only access.
41 | public AlternateView(string fileName) : base(fileName)
42 | {
43 | }
44 |
45 | ///
Initializes a new instance of with the specified file name and media type.
46 | ///
The name of the file that contains the content for this alternate view.
47 | ///
The MIME media type of the content.
48 | ///
49 | /// is null.
50 | ///
51 | /// is not a valid value.
52 | ///
The caller does not have the required permission.
53 | ///
An I/O error occurred, such as a disk error.
54 | ///
The access requested is not permitted by the operating system for the specified file handle, such as when access is Write or ReadWrite and the file handle is set for read-only access.
55 | public AlternateView(string fileName, string mediaType) : base(fileName, mediaType)
56 | {
57 | }
58 |
59 | ///
Initializes a new instance of with the specified file name and content type.
60 | ///
The name of the file that contains the content for this alternate view.
61 | ///
The type of the content.
62 | ///
63 | /// is null.
64 | ///
65 | /// is not a valid value.
66 | ///
The caller does not have the required permission.
67 | ///
An I/O error occurred, such as a disk error.
68 | ///
The access requested is not permitted by the operating system for the specified file handle, such as when access is Write or ReadWrite and the file handle is set for read-only access.
69 | public AlternateView(string fileName, ContentType contentType)
70 | {
71 | }
72 |
73 | ///
Initializes a new instance of with the specified .
74 | ///
A stream that contains the content for this view.
75 | ///
76 | /// is null.
77 | public AlternateView(Stream contentStream) : base(contentStream)
78 | {
79 | }
80 |
81 | ///
Initializes a new instance of with the specified and media type.
82 | ///
A stream that contains the content for this attachment.
83 | ///
The MIME media type of the content.
84 | ///
85 | /// is null.
86 | ///
87 | /// is not a valid value.
88 | public AlternateView(Stream contentStream, string mediaType) : base(contentStream, "", mediaType)
89 | {
90 | }
91 |
92 | ///
Initializes a new instance of with the specified and .
93 | ///
A stream that contains the content for this attachment.
94 | ///
The type of the content.
95 | ///
96 | /// is null.
97 | ///
98 | /// is not a valid value.
99 | public AlternateView(Stream contentStream, ContentType contentType) : base(contentStream, contentType)
100 | {
101 | }
102 | #endregion Constructors
103 |
104 | #region Public Methods
105 | ///
Creates a of an email message using the content specified in a .
106 | ///
An object that represents an alternate view of an email message.
107 | ///
The
that contains the content of the email message.
108 | ///
109 | /// is null.
110 | public static AlternateView CreateAlternateViewFromString(string content)
111 | {
112 | AlternateView alternateView = new AlternateView();
113 | alternateView.ContentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
114 | return alternateView;
115 | }
116 |
117 | ///
Creates an of an email message using the content specified in a , the specified text encoding, and MIME media type of the content.
118 | ///
An object that represents an alternate view of an email message.
119 | ///
A
that contains the content for this attachment.
120 | ///
An
. This value can be null.
121 | ///
The MIME media type of the content.
122 | ///
123 | /// is null.
124 | public static AlternateView CreateAlternateViewFromString(string content, Encoding contentEncoding, string mediaType)
125 | {
126 | AlternateView alternateView = new AlternateView();
127 | alternateView.ContentStream = new MemoryStream(contentEncoding.GetBytes(content));
128 | alternateView.MediaType = mediaType;
129 | return alternateView;
130 | }
131 |
132 | ///
Creates an of an email message using the content specified in a and the specified MIME media type of the content.
133 | ///
An object that represents an alternate view of an email message.
134 | ///
A
that contains the content for this attachment.
135 | ///
A
that describes the data in
.
136 | ///
137 | /// is null.
138 | public static AlternateView CreateAlternateViewFromString(string content, ContentType contentType)
139 | {
140 | AlternateView alternateView = new AlternateView();
141 | alternateView.ContentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
142 | alternateView.MediaType = contentType.MediaType;
143 | return alternateView;
144 | }
145 | #endregion Public Methods
146 | }
147 |
148 | public class AlternateViewCollection : Collection
149 | {
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/OpaqueMail/Attachment.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System.Collections.ObjectModel;
17 | using System.IO;
18 | using System.Text;
19 |
20 | namespace OpaqueMail
21 | {
22 | public class Attachment
23 | {
24 | public string Boundary { get; set; }
25 | public string ContentId { get; set; }
26 | public string MediaType { get; set; }
27 | public string Name { get; set; }
28 | public Encoding NameEncoding { get; set; }
29 | public Stream ContentStream { get; set; }
30 |
31 | public Attachment()
32 | {
33 | ContentStream = new MemoryStream();
34 | }
35 |
36 | public Attachment(string fileName)
37 | {
38 | FileInfo fi = new FileInfo(fileName);
39 | ContentStream = new MemoryStream(File.ReadAllBytes(fileName));
40 | ContentStream.Seek(0, SeekOrigin.Begin);
41 | Name = fi.Name;
42 | }
43 |
44 | public Attachment(string fileName, string mediaType)
45 | {
46 | FileInfo fi = new FileInfo(fileName);
47 | ContentStream = new MemoryStream(File.ReadAllBytes(fileName));
48 | ContentStream.Seek(0, SeekOrigin.Begin);
49 | Name = fi.Name;
50 | MediaType = mediaType;
51 | }
52 |
53 | public Attachment(string fileName, ContentType contentType)
54 | {
55 | FileInfo fi = new FileInfo(fileName);
56 | ContentStream = new MemoryStream(File.ReadAllBytes(fileName));
57 | ContentStream.Seek(0, SeekOrigin.Begin);
58 | Name = fi.Name;
59 |
60 | MediaType = contentType.MediaType;
61 | Boundary = contentType.Boundary;
62 | }
63 |
64 | public Attachment(Stream contentStream)
65 | : this()
66 | {
67 | contentStream.CopyTo(ContentStream);
68 | ContentStream.Seek(0, SeekOrigin.Begin);
69 | }
70 |
71 | public Attachment(Stream contentStream, string name)
72 | : this()
73 | {
74 | Name = name;
75 | contentStream.CopyTo(ContentStream);
76 | ContentStream.Seek(0, SeekOrigin.Begin);
77 | }
78 |
79 | public Attachment(Stream contentStream, string name, string mediaType)
80 | : this()
81 | {
82 | Name = name;
83 | contentStream.CopyTo(ContentStream);
84 | ContentStream.Seek(0, SeekOrigin.Begin);
85 | MediaType = mediaType;
86 | }
87 |
88 | public Attachment(Stream contentStream, ContentType contentType)
89 | : this()
90 | {
91 | contentStream.CopyTo(ContentStream);
92 | ContentStream.Seek(0, SeekOrigin.Begin);
93 | Name = contentType.Name;
94 | MediaType = contentType.MediaType;
95 | Boundary = contentType.Boundary;
96 | }
97 |
98 | /// Releases the unmanaged resources used by the and optionally releases the managed resources.
99 | /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
100 | protected void Dispose(bool disposing)
101 | {
102 | if (ContentStream != null)
103 | ContentStream.Dispose();
104 | }
105 | }
106 |
107 | public class AttachmentCollection : Collection
108 | {
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/OpaqueMail/Constants.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System;
17 | using System.Collections.Generic;
18 | using System.Linq;
19 | using System.Text;
20 | using System.Threading.Tasks;
21 |
22 | namespace OpaqueMail
23 | {
24 | ///
25 | /// Define constants used by other OpaqueMail classes.
26 | ///
27 | public static class Constants
28 | {
29 | ///
30 | /// Extra large buffer size for bit shuffling.
31 | ///
32 | public const int HUGEBUFFERSIZE = 16777216;
33 |
34 | ///
35 | /// Large buffer size for bit shuffling.
36 | ///
37 | public const int LARGEBUFFERSIZE = 1048576;
38 |
39 | ///
40 | /// Small buffer size for bit shuffling.
41 | ///
42 | public const int SMALLBUFFERSIZE = 65536;
43 |
44 | ///
45 | /// Tiny buffer size for bit shuffling.
46 | ///
47 | public const int TINYBUFFERSIZE = 2048;
48 |
49 | ///
50 | /// Tiny buffer size for string concatenation.
51 | ///
52 | public const int TINYSBSIZE = 256;
53 |
54 | ///
55 | /// Small buffer size for string concatenation.
56 | ///
57 | public const int SMALLSBSIZE = 2048;
58 |
59 | ///
60 | /// Medium buffer size for string concatenation.
61 | ///
62 | public const int MEDIUMSBSIZE = 32768;
63 |
64 | ///
65 | /// Large buffer size for string concatenation.
66 | ///
67 | public const int LARGESBSIZE = 1048576;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/OpaqueMail/LockAsync.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System;
17 | using System.Collections.Generic;
18 | using System.Threading;
19 | using System.Threading.Tasks;
20 |
21 | namespace OpaqueMail
22 | {
23 | ///
24 | /// Thread-safe asynchronous lock.
25 | ///
26 | ///
27 | /// See AsyncSemaphore and AsyncLock code by Stephen Toub. http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx
28 | ///
29 | public class AsyncLock
30 | {
31 | private readonly AsyncSemaphore semaphore;
32 | private readonly Task releaser;
33 |
34 | public AsyncLock()
35 | {
36 | semaphore = new AsyncSemaphore(1);
37 | releaser = Task.FromResult(new Releaser(this));
38 | }
39 |
40 | public Task LockAsync()
41 | {
42 | Task wait = semaphore.WaitAsync();
43 | return wait.IsCompleted ? releaser : wait.ContinueWith((_, state) => new Releaser((AsyncLock)state), this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
44 | }
45 |
46 | ///
47 | /// Helper class for unlocking.
48 | ///
49 | public struct Releaser : IDisposable
50 | {
51 | private readonly AsyncLock lockToRelease;
52 |
53 | internal Releaser(AsyncLock toRelease)
54 | {
55 | lockToRelease = toRelease;
56 | }
57 |
58 | public void Dispose()
59 | {
60 | if (lockToRelease != null)
61 | lockToRelease.semaphore.Release();
62 | }
63 | }
64 | }
65 |
66 | ///
67 | /// Thread-safe asynchronous semaphore.
68 | ///
69 | ///
70 | /// See AsyncSemaphore and AsyncLock code by Stephen Toub. http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx
71 | ///
72 | public class AsyncSemaphore
73 | {
74 | private readonly static Task completed = Task.FromResult(true);
75 | private readonly Queue> waiters = new Queue>();
76 | private int semaphoreCount;
77 |
78 | public AsyncSemaphore(int initialCount)
79 | {
80 | if (initialCount < 0)
81 | throw new ArgumentOutOfRangeException("Initial semaphore count out of range.");
82 |
83 | semaphoreCount = initialCount;
84 | }
85 |
86 | public Task WaitAsync()
87 | {
88 | lock (waiters)
89 | {
90 | if (semaphoreCount > 0)
91 | {
92 | --semaphoreCount;
93 | return completed;
94 | }
95 | else
96 | {
97 | TaskCompletionSource waiter = new TaskCompletionSource();
98 | waiters.Enqueue(waiter);
99 | return waiter.Task;
100 | }
101 | }
102 | }
103 |
104 | public void Release()
105 | {
106 | TaskCompletionSource toRelease = null;
107 |
108 | lock (waiters)
109 | {
110 | if (waiters.Count > 0)
111 | toRelease = waiters.Dequeue();
112 | else
113 | ++semaphoreCount;
114 | }
115 |
116 | if (toRelease != null)
117 | toRelease.SetResult(true);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/OpaqueMail/MailMessage.Smime.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System.Security.Cryptography.X509Certificates;
17 |
18 | namespace OpaqueMail
19 | {
20 | ///
21 | /// Represents an email message that was either received using the ImapClient or Pop3Client classes or will be sent using the SmtpClient class.
22 | /// Includes OpaqueMail extensions to facilitate handling of secure PGP and S/MIME messages.
23 | ///
24 | public partial class MailMessage
25 | {
26 | #region Public Members
27 | /// Encrypt the email's envelope. When SmimeSign is true, encryption is the second S/MIME operation.
28 | public bool SmimeEncryptedEnvelope { get; set; }
29 | /// Determine how the S/MIME envelope will be encrypted.
30 | /// Type of subject identifier to use.
31 | /// The default of "IssuerAndSerialNumber" is recommended for most use cases.
32 | public SmimeEncryptionOptionFlags SmimeEncryptionOptionFlags { get; set; }
33 | /// Whether S/MIME settings for encryption and signing are explicitly required or only preferred.
34 | public SmimeSettingsMode SmimeSettingsMode { get; set; }
35 | /// Sign the email. When true, signing is the first S/MIME operation.
36 | public bool SmimeSigned { get; set; }
37 | ///
38 | /// Certificate used when signing messages.
39 | /// Requires private key.
40 | ///
41 | public X509Certificate2 SmimeSigningCertificate { get; set; }
42 | /// Certificate chain used to sign the message.
43 | public X509Certificate2Collection SmimeSigningCertificateChain { get; set; }
44 | /// Determine how the S/MIME message will be signed.
45 | public SmimeSigningOptionFlags SmimeSigningOptionFlags { get; set; }
46 | /// Triple-wrap the email by signing, then encrypting the envelope, then signing the encrypted envelope.
47 | public bool SmimeTripleWrapped { get; set; }
48 | #endregion Public Members
49 |
50 | #region Protected Members
51 | /// Text delimiting S/MIME message parts related to signatures.
52 | protected string SmimeSignedCmsBoundaryName = "OpaqueMail-signature-boundary";
53 | /// Text delimiting MIME message parts in triple wrapped messages.
54 | protected string SmimeTripleSignedCmsBoundaryName = "OpaqueMail-triple-signature-boundary";
55 | #endregion Protected Members
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/OpaqueMail/Mailbox.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System;
17 | using System.Collections.Generic;
18 |
19 | namespace OpaqueMail
20 | {
21 | ///
22 | /// Represents an IMAP mailbox.
23 | ///
24 | public class Mailbox
25 | {
26 | /// List of FETCH commands returned by QRESYNC.
27 | public List FetchList { get; set; }
28 | /// Standard IMAP flags associated with this mailbox.
29 | public HashSet Flags { get; set; }
30 | /// Mailbox hierarchy delimiting string.
31 | public string HierarchyDelimiter { get; set; }
32 | /// Name of the mailbox.
33 | public string Name { get; set; }
34 | /// True if ModSeq is explicitly unavailable.
35 | public bool NoModSeq { get; set; }
36 | /// Permanent IMAP flags associated with this mailbox.
37 | public HashSet PermanentFlags { get; set; }
38 | /// List of message IDs that have disappeared since the last QRESYNC.
39 | public string VanishedList { get; set; }
40 |
41 | /// Number of messages in the mailbox. Null if COUNT was not parsed.
42 | public int? Count { get; set; }
43 | /// Highest ModSeq in the mailbox. Null if HIGHESTMODSEQ was not parsed.
44 | public int? HighestModSeq { get; set; }
45 | /// Number of recent messages in the mailbox. Null if RECENT was not parsed.
46 | public int? Recent { get; set; }
47 | /// Expected next UID for the mailbox. Null if UIDNEXT was not parsed.
48 | public int? UidNext { get; set; }
49 | /// UID validity for the mailbox. Null if UIDVALIDITY was not parsed.
50 | public int? UidValidity { get; set; }
51 |
52 | #region Constructors
53 | ///
54 | /// Default constructor.
55 | ///
56 | public Mailbox()
57 | {
58 | FetchList = new List();
59 | Flags = new HashSet();
60 | NoModSeq = false;
61 | PermanentFlags = new HashSet();
62 |
63 | Count = null;
64 | HighestModSeq = null;
65 | Recent = null;
66 | UidNext = null;
67 | UidValidity = null;
68 | }
69 |
70 | ///
71 | /// Parse IMAP output from an EXAMINE or SELECT command.
72 | ///
73 | /// Name of the mailbox.
74 | /// Raw IMAP output of an EXAMINE or SELECT command.
75 | public Mailbox(string name, string imapResponse)
76 | : this()
77 | {
78 | // Escape modifed UTF-7 encoding for ampersands or Unicode characters.
79 | Name = Functions.FromModifiedUTF7(name);
80 |
81 | string[] responseLines = imapResponse.Replace("\r", "").Split('\n');
82 | foreach (string responseLine in responseLines)
83 | {
84 | if (responseLine.StartsWith("* FLAGS ("))
85 | {
86 | string[] flags = responseLine.Substring(9, responseLine.Length - 10).Split(' ');
87 | foreach (string flag in flags)
88 | {
89 | if (!Flags.Contains(flag))
90 | Flags.Add(flag);
91 | }
92 | }
93 | else if (responseLine.StartsWith("* OK [NOMODSEQ]"))
94 | NoModSeq = true;
95 | else if (responseLine.StartsWith("* OK [HIGHESTMODSEQ "))
96 | {
97 | string highestModSeq = responseLine.Substring(20, responseLine.IndexOf("]") - 20);
98 | int highestModSeqValue;
99 | int.TryParse(highestModSeq, out highestModSeqValue);
100 | HighestModSeq = highestModSeqValue;
101 | }
102 | else if (responseLine.StartsWith("* OK [PERMANENTFLAGS ("))
103 | {
104 | string[] permanentFlags = responseLine.Substring(22, responseLine.IndexOf("]") - 22).Split(' ');
105 | foreach (string permanentFlag in permanentFlags)
106 | {
107 | if (!PermanentFlags.Contains(permanentFlag))
108 | PermanentFlags.Add(permanentFlag);
109 | }
110 | }
111 | else if (responseLine.StartsWith("* OK [UIDNEXT "))
112 | {
113 | string uidNext = responseLine.Substring(14, responseLine.IndexOf("]") - 14);
114 | int uidNextValue;
115 | int.TryParse(uidNext, out uidNextValue);
116 | UidNext = uidNextValue;
117 | }
118 | else if (responseLine.StartsWith("* OK [UIDVALIDITY "))
119 | {
120 | string uidValidity = responseLine.Substring(18, responseLine.IndexOf("]") - 18);
121 | int UidValidityValue;
122 | int.TryParse(uidValidity, out UidValidityValue);
123 | UidValidity = UidValidityValue;
124 | }
125 | else if (responseLine.StartsWith("* VANISHED "))
126 | VanishedList = responseLine.Substring(11);
127 | else if (responseLine.IndexOf(" FETCH ", StringComparison.Ordinal) > -1)
128 | FetchList.Add(responseLine);
129 | else if (responseLine.EndsWith(" EXISTS"))
130 | {
131 | string existsCount = responseLine.Substring(2, responseLine.Length - 9);
132 | int existsCountValue;
133 | int.TryParse(existsCount, out existsCountValue);
134 | Count = existsCountValue;
135 | }
136 | else if (responseLine.EndsWith(" RECENT"))
137 | {
138 | string recentCount = responseLine.Substring(2, responseLine.Length - 9);
139 | int recentCountValue;
140 | int.TryParse(recentCount, out recentCountValue);
141 | Recent = recentCountValue;
142 | }
143 | }
144 | }
145 |
146 | ///
147 | /// Parse IMAP output from a LIST, LSUB, or XLIST command.
148 | ///
149 | /// Raw output line from a LIST, LSUB, or XLIST command.
150 | ///
151 | public static Mailbox CreateFromList(string lineFromListCommand)
152 | {
153 | // Ensure the list of flags is contained on this line.
154 | int startsFlagList = lineFromListCommand.IndexOf("(");
155 | int endFlagList = lineFromListCommand.IndexOf(")", startsFlagList + 1);
156 | if (startsFlagList > -1 && endFlagList > -1)
157 | {
158 | Mailbox mailbox = new Mailbox();
159 |
160 | string[] flags = lineFromListCommand.Substring(startsFlagList + 1, endFlagList - startsFlagList - 1).Split(' ');
161 | foreach (string flag in flags)
162 | {
163 | if (!mailbox.Flags.Contains(flag))
164 | mailbox.Flags.Add(flag);
165 | }
166 |
167 | // Ensure the hierarchy delimiter and name are returned.
168 | string[] remainingParts = lineFromListCommand.Substring(endFlagList + 2).Split(new char[] { ' ' }, 2);
169 | if (remainingParts.Length == 2)
170 | {
171 | mailbox.HierarchyDelimiter = remainingParts[0].Replace("\"", "");
172 |
173 | // Escape modifed UTF-7 encoding for ampersands or Unicode characters.
174 | mailbox.Name = Functions.FromModifiedUTF7(remainingParts[1].Replace("\"", ""));
175 |
176 | return mailbox;
177 | }
178 | }
179 |
180 | // No valid mailbox listing found, so return null.
181 | return null;
182 | }
183 | #endregion Constructors
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/OpaqueMail/OpaqueMail.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BF21D27F-72AD-492E-8219-6C82C2330C72}
8 | Library
9 | Properties
10 | OpaqueMail
11 | OpaqueMail
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 | true
34 |
35 |
36 | OpaqueMail.pfx
37 |
38 |
39 |
40 | ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll
41 | True
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
87 |
--------------------------------------------------------------------------------
/OpaqueMail/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System.Reflection;
17 | using System.Runtime.CompilerServices;
18 | using System.Runtime.InteropServices;
19 |
20 | // General Information about an assembly is controlled through the following
21 | // set of attributes. Change these attribute values to modify the information
22 | // associated with an assembly.
23 | [assembly: AssemblyTitle("OpaqueMail")]
24 | [assembly: AssemblyDescription(".NET email library with full support for IMAP, POP3, SMTP, and S/MIME encryption.")]
25 | [assembly: AssemblyConfiguration("")]
26 | [assembly: AssemblyCompany("Bert Johnson")]
27 | [assembly: AssemblyProduct("OpaqueMail")]
28 | [assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
29 | [assembly: AssemblyTrademark("")]
30 | [assembly: AssemblyCulture("")]
31 |
32 | // Setting ComVisible to false makes the types in this assembly not visible
33 | // to COM components. If you need to access a type in this assembly from
34 | // COM, set the ComVisible attribute to true on that type.
35 | [assembly: ComVisible(false)]
36 |
37 | // The following GUID is for the ID of the typelib if this project is exposed to COM
38 | [assembly: Guid("0ee540e1-57f7-4188-81b1-4dede5ff78fc")]
39 |
40 | // Version information for an assembly consists of the following four values:
41 | //
42 | // Major Version
43 | // Minor Version
44 | // Build Number
45 | // Revision
46 | //
47 | // You can specify all the values or you can default the Build and Revision Numbers
48 | // by using the '*' as shown below:
49 | // [assembly: AssemblyVersion("1.0.*")]
50 | [assembly: AssemblyVersion("2.5.4")]
51 | [assembly: AssemblyFileVersion("2.5.4")]
52 |
--------------------------------------------------------------------------------
/OpaqueMail/Smtp/SmtpClient.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * OpaqueMail (https://opaquemail.org/).
3 | *
4 | * Licensed according to the MIT License (http://mit-license.org/).
5 | *
6 | * Copyright © Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | *
12 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | *
14 | */
15 |
16 | using System;
17 | using System.IO;
18 | using System.Net;
19 | using System.Net.Security;
20 | using System.Net.Sockets;
21 | using System.Security.Authentication;
22 | using System.Security.Cryptography;
23 | using System.Security.Cryptography.Pkcs;
24 | using System.Text;
25 | using System.Threading.Tasks;
26 |
27 | namespace OpaqueMail
28 | {
29 | ///
30 | /// Allows applications to send email by using the Simple Mail Transport Protocol (SMTP).
31 | /// Includes OpaqueMail extensions to facilitate sending of secure S/MIME messages.
32 | ///
33 | public partial class SmtpClient : System.Net.Mail.SmtpClient
34 | {
35 | #region Public Members
36 | /// Allowed protocols when EnableSSL is true.
37 | public SslProtocols SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
38 | #endregion Public Members
39 |
40 | #region Private Members
41 | /// Buffer used during various S/MIME operations.
42 | private byte[] buffer = new byte[Constants.HUGEBUFFERSIZE];
43 | #endregion Private Members
44 |
45 | #region Constructors
46 | ///
47 | /// Initializes a new instance of the OpaqueMail.SmtpClient class by using configuration file settings.
48 | ///
49 | public SmtpClient()
50 | : base()
51 | {
52 | SmimeAlgorithmIdentifier = new AlgorithmIdentifier(new Oid("2.16.840.1.101.3.4.1.42"));
53 | SmimeValidCertificates = null;
54 |
55 | RandomizeBoundaryNames();
56 |
57 | EnableSsl = true;
58 | }
59 | ///
60 | /// Initializes a new instance of the OpaqueMail.SmtpClient class that sends email by using the specified SMTP server.
61 | ///
62 | /// Name or IP of the host used for SMTP transactions.
63 | public SmtpClient(string host)
64 | : base(host)
65 | {
66 | SmimeAlgorithmIdentifier = new AlgorithmIdentifier(new Oid("2.16.840.1.101.3.4.1.42"));
67 | SmimeValidCertificates = null;
68 |
69 | RandomizeBoundaryNames();
70 | }
71 | ///
72 | /// Initializes a new instance of the OpaqueMail.SmtpClient class that sends email by using the specified SMTP server and port.
73 | ///
74 | /// Name or IP of the host used for SMTP transactions.
75 | /// Port to be used by the host.
76 | public SmtpClient(string host, int port)
77 | : base(host, port)
78 | {
79 | SmimeAlgorithmIdentifier = new AlgorithmIdentifier(new Oid("2.16.840.1.101.3.4.1.42"));
80 | SmimeValidCertificates = null;
81 |
82 | RandomizeBoundaryNames();
83 | }
84 | #endregion Constructors
85 |
86 | #region Public Methods
87 | ///
88 | /// Sends the specified message to an SMTP server for delivery.
89 | ///
90 | /// An OpaqueMail.MailMessage that contains the message to send.
91 | public void Send(MailMessage message)
92 | {
93 | Task.Run(() => SendAsync(message)).Wait();
94 | }
95 |
96 | ///
97 | /// Sends the specified message to an SMTP server for delivery.
98 | ///
99 | /// An OpaqueMail.MailMessage that contains the message to send.
100 | public async Task SendAsync(MailMessage message)
101 | {
102 | // If the message isn't encoded, do so now.
103 | if (string.IsNullOrEmpty(message.RawBody))
104 | message.Prepare();
105 |
106 | // Perform requested S/MIME signing and/or encryption.
107 | message.SmimePrepare(this);
108 | string rawBody = message.RawBody;
109 |
110 | // Connect to the SMTP server.
111 | TcpClient SmtpTcpClient = new TcpClient();
112 | SmtpTcpClient.Connect(Host, Port);
113 | Stream SmtpStream = SmtpTcpClient.GetStream();
114 |
115 | // Use stream readers and writers to simplify I/O.
116 | StreamReader reader = new StreamReader(SmtpStream);
117 | StreamWriter writer = new StreamWriter(SmtpStream);
118 | writer.AutoFlush = true;
119 |
120 | // Read the welcome message.
121 | string response = await reader.ReadLineAsync();
122 |
123 | // Send EHLO and find out server capabilities.
124 | await writer.WriteLineAsync("EHLO " + Host);
125 | char[] charBuffer = new char[Constants.SMALLBUFFERSIZE];
126 | int bytesRead = await reader.ReadAsync(charBuffer, 0, Constants.SMALLBUFFERSIZE);
127 | response = new string(charBuffer, 0, bytesRead);
128 | if (!response.StartsWith("2"))
129 | throw new SmtpException("Unable to connect to remote server '" + Host + "'. Sent 'EHLO' and received '" + response + "'.");
130 |
131 | // Stand up a TLS/SSL stream.
132 | if (EnableSsl)
133 | {
134 | await writer.WriteLineAsync("STARTTLS");
135 | response = await reader.ReadLineAsync();
136 | if (!response.StartsWith("2"))
137 | throw new SmtpException("Unable to start TLS/SSL protection with '" + Host + "'. Received '" + response + "'.");
138 |
139 | SmtpStream = new SslStream(SmtpStream);
140 | ((SslStream)SmtpStream).AuthenticateAsClient(Host, null, SslProtocols, true);
141 |
142 | reader = new StreamReader(SmtpStream);
143 | writer = new StreamWriter(SmtpStream);
144 | writer.AutoFlush = true;
145 |
146 | await writer.WriteLineAsync("EHLO " + Host);
147 | bytesRead = await reader.ReadAsync(charBuffer, 0, Constants.SMALLBUFFERSIZE);
148 | response = new string(charBuffer, 0, bytesRead);
149 | }
150 |
151 | // Authenticate using the AUTH LOGIN command.
152 | if (Credentials != null)
153 | {
154 | NetworkCredential cred = (NetworkCredential)Credentials;
155 | await writer.WriteLineAsync("AUTH LOGIN");
156 | response = await reader.ReadLineAsync();
157 | if (!response.StartsWith("3"))
158 | throw new SmtpException("Unable to authenticate with server '" + Host + "'. Received '" + response + "'.");
159 | await writer.WriteLineAsync(Functions.ToBase64String(cred.UserName));
160 | string tempResponse = await reader.ReadLineAsync();
161 | await writer.WriteLineAsync(Functions.ToBase64String(cred.Password));
162 | response = await reader.ReadLineAsync();
163 | if (!response.StartsWith("2"))
164 | throw new SmtpException("Unable to authenticate with server '" + Host + "'. Received '" + response + "'.");
165 | }
166 |
167 | // Build our raw headers block.
168 | StringBuilder rawHeaders = new StringBuilder(Constants.SMALLSBSIZE);
169 |
170 | // Specify who the message is from.
171 | rawHeaders.Append(Functions.SpanHeaderLines("From: " + Functions.EncodeMailHeader(Functions.ToMailAddressString(message.From))) + "\r\n");
172 | await writer.WriteLineAsync("MAIL FROM:<" + message.From.Address + ">");
173 | response = await reader.ReadLineAsync();
174 | if (!response.StartsWith("2"))
175 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'MAIL FROM' and received '" + response + "'.");
176 |
177 | // Identify all recipients of the message.
178 | if (message.To.Count > 0)
179 | rawHeaders.Append(Functions.SpanHeaderLines("To: " + Functions.EncodeMailHeader(message.To.ToString())) + "\r\n");
180 | foreach (MailAddress address in message.To)
181 | {
182 | await writer.WriteLineAsync("RCPT TO:<" + address.Address + ">");
183 | response = await reader.ReadLineAsync();
184 | if (!response.StartsWith("2"))
185 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'RCPT TO' and received '" + response + "'.");
186 | }
187 |
188 | if (message.CC.Count > 0)
189 | rawHeaders.Append(Functions.SpanHeaderLines("CC: " + Functions.EncodeMailHeader(message.CC.ToString())) + "\r\n");
190 | foreach (MailAddress address in message.CC)
191 | {
192 | await writer.WriteLineAsync("RCPT TO:<" + address.Address + ">");
193 | response = await reader.ReadLineAsync();
194 | if (!response.StartsWith("2"))
195 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'RCPT TO' and received '" + response + "'.");
196 | }
197 |
198 | foreach (MailAddress address in message.Bcc)
199 | {
200 | await writer.WriteLineAsync("RCPT TO:<" + address.Address + ">");
201 | response = await reader.ReadLineAsync();
202 | if (!response.StartsWith("2"))
203 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'RCPT TO' and received '" + response + "'.");
204 | }
205 |
206 | // Ensure a content type is set.
207 | if (string.IsNullOrEmpty(message.ContentType))
208 | {
209 | if (Functions.AppearsHTML(message.Body))
210 | message.ContentType = "text/html";
211 | else
212 | message.ContentType = "text/plain";
213 | }
214 | message.Headers["Content-Type"] = message.ContentType + (!string.IsNullOrEmpty(message.CharSet) ? "; charset=\"" + message.CharSet + "\"" : "");
215 |
216 | // If the body hasn't been processed, handle encoding of extended characters.
217 | if (string.IsNullOrEmpty(rawBody) && !string.IsNullOrEmpty(message.Body))
218 | {
219 | bool extendedCharacterFound = false;
220 | foreach (char headerCharacter in message.Body.ToCharArray())
221 | {
222 | if (headerCharacter > 127)
223 | {
224 | extendedCharacterFound = true;
225 | break;
226 | }
227 | }
228 |
229 | if (extendedCharacterFound)
230 | {
231 | message.ContentTransferEncoding = "base64";
232 | message.Body = Functions.ToBase64String(message.Body);
233 | }
234 |
235 | rawBody = message.Body;
236 | }
237 |
238 | if (!string.IsNullOrEmpty(message.ContentTransferEncoding))
239 | message.Headers["Content-Transfer-Encoding"] = message.ContentTransferEncoding;
240 |
241 | // Send the raw message.
242 | await writer.WriteLineAsync("DATA");
243 | response = await reader.ReadLineAsync();
244 | if (!response.StartsWith("3"))
245 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'DATA' and received '" + response + "'.");
246 |
247 | rawHeaders.Append(Functions.SpanHeaderLines("Subject: " + Functions.EncodeMailHeader(message.Subject, 32)) + "\r\n");
248 | foreach (string rawHeader in message.Headers)
249 | {
250 | switch (rawHeader.ToUpper())
251 | {
252 | case "BCC":
253 | case "CC":
254 | case "FROM":
255 | case "SUBJECT":
256 | case "TO":
257 | break;
258 | default:
259 | rawHeaders.Append(Functions.SpanHeaderLines(rawHeader + ": " + message.Headers[rawHeader]) + "\r\n");
260 | break;
261 | }
262 | }
263 |
264 | await writer.WriteAsync(rawHeaders.ToString() + "\r\n" + rawBody + "\r\n.\r\n");
265 |
266 | response = await reader.ReadLineAsync();
267 | if (!response.StartsWith("2"))
268 | throw new SmtpException("Exception communicating with server '" + Host + "'. Sent message and received '" + response + "'.");
269 |
270 | // Clean up this connection.
271 | await writer.WriteLineAsync("QUIT");
272 |
273 | writer.Dispose();
274 | reader.Dispose();
275 |
276 | SmtpStream.Dispose();
277 | SmtpTcpClient.Close();
278 | }
279 | #endregion Public Methods
280 |
281 | #region Private Methods
282 | ///
283 | /// Ensure boundary names are unique.
284 | ///
285 | private void RandomizeBoundaryNames()
286 | {
287 | string boundaryRandomness = "";
288 | Random randomGenerator = new Random();
289 |
290 | // Append 10 random characters.
291 | for (int i = 0; i < 10; i++)
292 | {
293 | int nextCharacter = randomGenerator.Next(1, 36);
294 | if (nextCharacter > 26)
295 | boundaryRandomness += (char)(47 + nextCharacter);
296 | else
297 | boundaryRandomness += (char)(64 + nextCharacter);
298 | }
299 |
300 | SmimeAlternativeViewBoundaryName += "-" + boundaryRandomness;
301 | SmimeBoundaryName += "-" + boundaryRandomness;
302 | SmimeSignedCmsBoundaryName += "-" + boundaryRandomness;
303 | SmimeTripleSignedCmsBoundaryName += "-" + boundaryRandomness;
304 | }
305 | #endregion Private Methods
306 | }
307 |
308 | ///
309 | /// Represents the exception that is thrown when the OpaqueMail.ImapClient is not able to complete an operation.
310 | ///
311 | public class SmtpException : Exception
312 | {
313 | ///
314 | /// Initializes a new instance of the OpaqueMail.SmtpException class.
315 | ///
316 | public SmtpException() : base() { }
317 | ///
318 | /// Initializes a new instance of the OpaqueMail.SmtpException class with the specified error message and inner exception.
319 | ///
320 | /// A System.String that describes the error that occurred.
321 | public SmtpException(string message) : base(message) { }
322 | ///
323 | /// Initializes a new instance of the OpaqueMail.SmtpException class with the specified error message and inner exception.
324 | ///
325 | /// A System.String that describes the error that occurred.
326 | /// The exception that is the cause of the current exception.
327 | public SmtpException(string message, Exception innerException) : base(message, innerException) { }
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/OpaqueMail/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Important
2 | **As of May 2017, this project is not actively maintained. A great alternative is [MailKit by jstedfast](https://github.com/jstedfast/MailKit).**
3 |
4 | OpaqueMail .NET Email Library
5 | ==============================
6 |
7 | .NET email library with full support for IMAP, POP3, and SMTP.
8 |
9 | Supports S/MIME and PGP message signing, encryption, and decryption to foster better email security and privacy.
10 |
11 | Follows IETF standards, implementing all IMAP4rev1, POP3, SMTP, and S/MIME 3.2 commands plus common extensions such as IDLE. Supports MIME, Unicode, and TNEF encoding.
12 |
13 | Includes a fully-featured test client that allows browsing and searching of IMAP and POP3 messages as well as sending of SMTP messages with encryption. Automatically embeds images into Text/HTML messages and strips Script tags.
14 |
15 | Features patterns similar to System.Net.Mail.MailMessage and System.Net.Mail.SmtpClient for simplified upgrades of existing code. Implements .NET 4.5 async and await.
16 |
17 | Thoroughly documented. Optimized for security, usability, and performance.
18 |
19 | Supporting documentation and tutorials available at https://github.com/bertjohnson/OpaqueMail/wiki/OpaqueMail-Library-Tutorial.
20 |
21 | Licensed according to the MIT License (http://mit-license.org/).
22 |
23 | Created by Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
24 |
25 | OpaqueMail Email Proxy
26 | ==============================
27 |
28 | SMTP proxy and message transfer agent (MTA) to add or remove S/MIME message signing, encryption, and authentication for outbound messages. Can operate in passthrough mode or augment messages to add or filter headers.
29 |
30 | Also serve as a passthrough IMAP and POP3 proxy to import S/MIME certificates, filter IPs, or export messages.
31 |
32 | Simplifies email protection for Outlook, Thunderbird, Windows Live Mail, Opera Mail, and other email clients.
33 |
34 | Can be used to secure and authenticate email programs that connect to SMTP servers anonymously (e.g. SharePoint).
35 |
36 | Runs as a Windows service. Inbound and outbound IPs, ports, logging, and TLS / SSL settings are all configurable via XML.
37 |
38 | Supporting documentation and tutorials available at https://github.com/bertjohnson/OpaqueMail/wiki/OpaqueMail-Proxy-Tutorial.
39 |
40 | Licensed according to the MIT License (http://mit-license.org/).
41 |
42 | Created by Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
43 |
44 | License
45 | =======
46 |
47 | Copyright © 2013-2017 Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
48 |
49 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
50 |
51 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
52 |
53 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54 |
--------------------------------------------------------------------------------
/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------